packages feed

swagger2 0.1 → 0.2

raw patch · 7 files changed

+1954/−742 lines, 7 filesdep +lens

Dependencies added: lens

Files

+ CHANGELOG.md view
@@ -0,0 +1,8 @@+0.2+---+* Add `Data.Swagger.Lens`+* Support references+* Fixes:+    * Fix `FromJSON SwaggerHost` instance+    * Add missing `Maybe`s for field types+    * Decode petstore swagger.json successfully
src/Data/Swagger.hs view
@@ -70,6 +70,10 @@   -- * External documentation   SwaggerExternalDocs(..), +  -- * References+  SwaggerReference(..),+  SwaggerReferenced(..),+   -- * Miscellaneous   SwaggerMimeList(..),   URL(..),
src/Data/Swagger/Internal.hs view
@@ -35,61 +35,61 @@ data Swagger = Swagger   { -- | Provides metadata about the API.     -- The metadata can be used by the clients if needed.-    swaggerInfo :: SwaggerInfo+    _swaggerInfo :: SwaggerInfo      -- | The host (name or ip) serving the API. It MAY include a port.     -- If the host is not included, the host serving the documentation is to be used (including the port).-  , swaggerHost :: Maybe SwaggerHost+  , _swaggerHost :: Maybe SwaggerHost      -- | The base path on which the API is served, which is relative to the host.     -- If it is not included, the API is served directly under the host.     -- The value MUST start with a leading slash (/).-  , swaggerBasePath :: Maybe FilePath+  , _swaggerBasePath :: Maybe FilePath      -- | The transfer protocol of the API.     -- If the schemes is not included, the default scheme to be used is the one used to access the Swagger definition itself.-  , swaggerSchemes :: Maybe [SwaggerScheme]+  , _swaggerSchemes :: Maybe [SwaggerScheme]      -- | A list of MIME types the APIs can consume.     -- This is global to all APIs but can be overridden on specific API calls.-  , swaggerConsumes :: SwaggerMimeList+  , _swaggerConsumes :: SwaggerMimeList      -- | A list of MIME types the APIs can produce.     -- This is global to all APIs but can be overridden on specific API calls. -  , swaggerProduces :: SwaggerMimeList+  , _swaggerProduces :: SwaggerMimeList      -- | The available paths and operations for the API.-  , swaggerPaths :: SwaggerPaths+  , _swaggerPaths :: SwaggerPaths      -- | An object to hold data types produced and consumed by operations.-  , swaggerDefinitions :: HashMap Text SwaggerSchema+  , _swaggerDefinitions :: HashMap Text SwaggerSchema      -- | An object to hold parameters that can be used across operations.     -- This property does not define global parameters for all operations.-  , swaggerParameters :: HashMap Text SwaggerParameter+  , _swaggerParameters :: HashMap Text SwaggerParameter      -- | An object to hold responses that can be used across operations.     -- This property does not define global responses for all operations.-  , swaggerResponses :: HashMap Text SwaggerResponse+  , _swaggerResponses :: HashMap Text SwaggerResponse      -- | Security scheme definitions that can be used across the specification.-  , swaggerSecurityDefinitions :: HashMap Text SwaggerSecurityScheme+  , _swaggerSecurityDefinitions :: HashMap Text SwaggerSecurityScheme      -- | A declaration of which security schemes are applied for the API as a whole.     -- The list of values describes alternative security schemes that can be used     -- (that is, there is a logical OR between the security requirements).     -- Individual operations can override this definition.-  , swaggerSecurity :: [SwaggerSecurityRequirement]+  , _swaggerSecurity :: [SwaggerSecurityRequirement]      -- | A list of tags used by the specification with additional metadata.     -- The order of the tags can be used to reflect on their order by the parsing tools.     -- Not all tags that are used by the Operation Object must be declared.     -- The tags that are not declared may be organized randomly or based on the tools' logic.     -- Each tag name in the list MUST be unique.-  , swaggerTags :: [SwaggerTag]+  , _swaggerTags :: [SwaggerTag]      -- | Additional external documentation.-  , swaggerExternalDocs :: Maybe SwaggerExternalDocs+  , _swaggerExternalDocs :: Maybe SwaggerExternalDocs   } deriving (Eq, Show, Generic)  -- | The object provides metadata about the API.@@ -97,51 +97,51 @@ -- and can be presented in the Swagger-UI for convenience. data SwaggerInfo = SwaggerInfo   { -- | The title of the application.-    swaggerInfoTitle :: Text+    _swaggerInfoTitle :: Text      -- | A short description of the application.     -- GFM syntax can be used for rich text representation.-  , swaggerInfoDescription :: Maybe Text+  , _swaggerInfoDescription :: Maybe Text      -- | The Terms of Service for the API.-  , swaggerInfoTermsOfService :: Maybe Text+  , _swaggerInfoTermsOfService :: Maybe Text      -- | The contact information for the exposed API.-  , swaggerInfoContact :: Maybe SwaggerContact+  , _swaggerInfoContact :: Maybe SwaggerContact      -- | The license information for the exposed API.-  , swaggerInfoLicense :: Maybe SwaggerLicense+  , _swaggerInfoLicense :: Maybe SwaggerLicense      -- | Provides the version of the application API     -- (not to be confused with the specification version).-  , swaggerInfoVersion :: Text+  , _swaggerInfoVersion :: Text   } deriving (Eq, Show, Generic)  -- | Contact information for the exposed API. data SwaggerContact = SwaggerContact   { -- | The identifying name of the contact person/organization.-    swaggerContactName  :: Maybe Text+    _swaggerContactName  :: Maybe Text      -- | The URL pointing to the contact information.-  , swaggerContactUrl   :: Maybe URL+  , _swaggerContactUrl   :: Maybe URL      -- | The email address of the contact person/organization.-  , swaggerContactEmail :: Maybe Text+  , _swaggerContactEmail :: Maybe Text   } deriving (Eq, Show)  -- | License information for the exposed API. data SwaggerLicense = SwaggerLicense   { -- | The license name used for the API.-    swaggerLicenseName :: Text+    _swaggerLicenseName :: Text      -- | A URL to the license used for the API.-  , swaggerLicenseUrl :: Maybe URL+  , _swaggerLicenseUrl :: Maybe URL   } deriving (Eq, Show)  -- | The host (name or ip) serving the API. It MAY include a port. data SwaggerHost = SwaggerHost-  { swaggerHostName :: HostName         -- ^ Host name.-  , swaggerHostPort :: Maybe PortNumber -- ^ Optional port.+  { _swaggerHostName :: HostName         -- ^ Host name.+  , _swaggerHostPort :: Maybe PortNumber -- ^ Optional port.   } deriving (Eq, Show)  -- | The transfer protocol of the API.@@ -156,7 +156,7 @@ data SwaggerPaths = SwaggerPaths   { -- | Holds the relative paths to the individual endpoints.     -- The path is appended to the @'swaggerBasePath'@ in order to construct the full URL.-    swaggerPathsMap         :: HashMap FilePath SwaggerPathItem+    _swaggerPathsMap         :: HashMap FilePath SwaggerPathItem   } deriving (Eq, Show, Generic)  -- | Describes the operations available on a single path.@@ -165,91 +165,91 @@ -- but they will not know which operations and parameters are available. data SwaggerPathItem = SwaggerPathItem   { -- | A definition of a GET operation on this path.-    swaggerPathItemGet :: Maybe SwaggerOperation+    _swaggerPathItemGet :: Maybe SwaggerOperation      -- | A definition of a PUT operation on this path.-  , swaggerPathItemPut :: Maybe SwaggerOperation+  , _swaggerPathItemPut :: Maybe SwaggerOperation      -- | A definition of a POST operation on this path.-  , swaggerPathItemPost :: Maybe SwaggerOperation+  , _swaggerPathItemPost :: Maybe SwaggerOperation      -- | A definition of a DELETE operation on this path.-  , swaggerPathItemDelete :: Maybe SwaggerOperation+  , _swaggerPathItemDelete :: Maybe SwaggerOperation      -- | A definition of a OPTIONS operation on this path.-  , swaggerPathItemOptions :: Maybe SwaggerOperation+  , _swaggerPathItemOptions :: Maybe SwaggerOperation      -- | A definition of a HEAD operation on this path.-  , swaggerPathItemHead :: Maybe SwaggerOperation+  , _swaggerPathItemHead :: Maybe SwaggerOperation      -- | A definition of a PATCH operation on this path.-  , swaggerPathItemPatch :: Maybe SwaggerOperation+  , _swaggerPathItemPatch :: Maybe SwaggerOperation      -- | A list of parameters that are applicable for all the operations described under this path.     -- These parameters can be overridden at the operation level, but cannot be removed there.     -- The list MUST NOT include duplicated parameters.     -- A unique parameter is defined by a combination of a name and location.-  , swaggerPathItemParameters :: [SwaggerParameter]+  , _swaggerPathItemParameters :: [SwaggerReferenced SwaggerParameter]   } deriving (Eq, Show, Generic)  -- | Describes a single API operation on a path. data SwaggerOperation = SwaggerOperation   { -- | A list of tags for API documentation control.     -- Tags can be used for logical grouping of operations by resources or any other qualifier.-    swaggerOperationTags :: [Text]+    _swaggerOperationTags :: [Text]      -- | A short summary of what the operation does.     -- For maximum readability in the swagger-ui, this field SHOULD be less than 120 characters.-  , swaggerOperationSummary :: Maybe Text+  , _swaggerOperationSummary :: Maybe Text      -- | A verbose explanation of the operation behavior.     -- GFM syntax can be used for rich text representation.-  , swaggerOperationDescription :: Maybe Text+  , _swaggerOperationDescription :: Maybe Text      -- | Additional external documentation for this operation.-  , swaggerOperationExternalDocs :: Maybe SwaggerExternalDocs+  , _swaggerOperationExternalDocs :: Maybe SwaggerExternalDocs      -- | Unique string used to identify the operation.     -- The id MUST be unique among all operations described in the API.     -- Tools and libraries MAY use the it to uniquely identify an operation,     -- therefore, it is recommended to follow common programming naming conventions.-  , swaggerOperationOperationId :: Maybe Text+  , _swaggerOperationOperationId :: Maybe Text      -- | A list of MIME types the operation can consume.     -- This overrides the @'swaggerConsumes'@.     -- @Just []@ MAY be used to clear the global definition.-  , swaggerOperationConsumes :: Maybe SwaggerMimeList+  , _swaggerOperationConsumes :: Maybe SwaggerMimeList      -- | A list of MIME types the operation can produce.     -- This overrides the @'swaggerProduces'@.     -- @Just []@ MAY be used to clear the global definition.-  , swaggerOperationProduces :: Maybe SwaggerMimeList+  , _swaggerOperationProduces :: Maybe SwaggerMimeList      -- | A list of parameters that are applicable for this operation.     -- If a parameter is already defined at the @'SwaggerPathItem'@,     -- the new definition will override it, but can never remove it.     -- The list MUST NOT include duplicated parameters.     -- A unique parameter is defined by a combination of a name and location.-  , swaggerOperationParameters :: [SwaggerParameter]+  , _swaggerOperationParameters :: [SwaggerReferenced SwaggerParameter]      -- | The list of possible responses as they are returned from executing this operation.-  , swaggerOperationResponses :: SwaggerResponses+  , _swaggerOperationResponses :: SwaggerResponses      -- | The transfer protocol for the operation.     -- The value overrides @'swaggerSchemes'@.-  , swaggerOperationSchemes :: Maybe [SwaggerScheme]+  , _swaggerOperationSchemes :: Maybe [SwaggerScheme]      -- | Declares this operation to be deprecated.     -- Usage of the declared operation should be refrained.     -- Default value is @False@.-  , swaggerOperationDeprecated :: Bool+  , _swaggerOperationDeprecated :: Bool      -- | A declaration of which security schemes are applied for this operation.     -- The list of values describes alternative security schemes that can be used     -- (that is, there is a logical OR between the security requirements).     -- This definition overrides any declared top-level security.     -- To remove a top-level security declaration, @Just []@ can be used.-  , swaggerOperationSecurity :: [SwaggerSecurityRequirement]+  , _swaggerOperationSecurity :: [SwaggerSecurityRequirement]   } deriving (Eq, Show, Generic)  newtype SwaggerMimeList = SwaggerMimeList { getSwaggerMimeList :: [MediaType] }@@ -260,30 +260,30 @@ data SwaggerParameter = SwaggerParameter   { -- | The name of the parameter.     -- Parameter names are case sensitive.-    swaggerParameterName :: Text+    _swaggerParameterName :: Text      -- | A brief description of the parameter.     -- This could contain examples of use.     -- GFM syntax can be used for rich text representation.-  , swaggerParameterDescription :: Maybe Text+  , _swaggerParameterDescription :: Maybe Text      -- | Determines whether this parameter is mandatory.     -- If the parameter is in "path", this property is required and its value MUST be true.     -- Otherwise, the property MAY be included and its default value is @False@.-  , swaggerParameterRequired :: Bool+  , _swaggerParameterRequired :: Bool      -- | Parameter schema.-  , swaggerParameterSchema :: SwaggerParameterSchema+  , _swaggerParameterSchema :: SwaggerParameterSchema   } deriving (Eq, Show, Generic)  data SwaggerParameterSchema-  = SwaggerParameterBody SwaggerSchema+  = SwaggerParameterBody (SwaggerReferenced SwaggerSchema)   | SwaggerParameterOther SwaggerParameterOtherSchema   deriving (Eq, Show)  data SwaggerParameterOtherSchema = SwaggerParameterOtherSchema   { -- | The location of the parameter.-    swaggerParameterOtherSchemaIn :: SwaggerParameterLocation+    _swaggerParameterOtherSchemaIn :: SwaggerParameterLocation      -- | The type of the parameter.     -- Since the parameter is not located at the request body,@@ -291,26 +291,26 @@     -- If type is @'SwaggerParamFile'@, the @consumes@ MUST be either     -- "multipart/form-data" or " application/x-www-form-urlencoded"     -- and the parameter MUST be in @'SwaggerParameterFormData'@.-  , swaggerParameterOtherSchemaType :: SwaggerParameterType+  , _swaggerParameterOtherSchemaType :: SwaggerParameterType      -- | The extending format for the previously mentioned type.-  , swaggerParameterOtherSchemaFormat :: Maybe SwaggerFormat+  , _swaggerParameterOtherSchemaFormat :: Maybe SwaggerFormat      -- | Sets the ability to pass empty-valued parameters.     -- This is valid only for either @'SwaggerParameterQuery'@ or @'SwaggerParameterFormData'@     -- and allows you to send a parameter with a name only or an empty value.     -- Default value is @False@.-  , swaggerParameterOtherSchemaAllowEmptyValue :: Bool+  , _swaggerParameterOtherSchemaAllowEmptyValue :: Bool      -- | __Required if type is @'SwaggerParamArray'@__.     -- Describes the type of items in the array.-  , swaggerParameterOtherSchemaItems :: Maybe SwaggerItems+  , _swaggerParameterOtherSchemaItems :: Maybe SwaggerItems      -- | Determines the format of the array if @'SwaggerParamArray'@ is used.     -- Default value is csv.-  , swaggerParameterOtherSchemaCollectionFormat :: Maybe SwaggerCollectionFormat+  , _swaggerParameterOtherSchemaCollectionFormat :: Maybe SwaggerCollectionFormat -  , swaggerParameterOtherSchemaCommon :: SwaggerSchemaCommon+  , _swaggerParameterOtherSchemaCommon :: SwaggerSchemaCommon   } deriving (Eq, Show, Generic)  data SwaggerParameterType@@ -384,32 +384,32 @@ type SwaggerParamName = Text  data SwaggerSchema = SwaggerSchema-  { swaggerSchemaType :: SwaggerSchemaType-  , swaggerSchemaFormat :: Maybe SwaggerFormat-  , swaggerSchemaTitle :: Maybe Text-  , swaggerSchemaDescription :: Maybe Text-  , swaggerSchemaRequired :: [SwaggerParamName]+  { _swaggerSchemaType :: SwaggerSchemaType+  , _swaggerSchemaFormat :: Maybe SwaggerFormat+  , _swaggerSchemaTitle :: Maybe Text+  , _swaggerSchemaDescription :: Maybe Text+  , _swaggerSchemaRequired :: [SwaggerParamName] -  , swaggerSchemaItems :: Maybe SwaggerSchemaItems-  , swaggerSchemaAllOf :: Maybe [SwaggerSchema]-  , swaggerSchemaProperties :: HashMap Text SwaggerSchema-  , swaggerSchemaAdditionalProperties :: Maybe SwaggerSchema+  , _swaggerSchemaItems :: Maybe SwaggerSchemaItems+  , _swaggerSchemaAllOf :: Maybe [SwaggerSchema]+  , _swaggerSchemaProperties :: HashMap Text (SwaggerReferenced SwaggerSchema)+  , _swaggerSchemaAdditionalProperties :: Maybe SwaggerSchema -  , swaggerSchemaDiscriminator :: Maybe Text-  , swaggerSchemaReadOnly :: Maybe Bool-  , swaggerSchemaXml :: Maybe SwaggerXml-  , swaggerSchemaExternalDocs :: Maybe SwaggerExternalDocs-  , swaggerSchemaExample :: Maybe Value+  , _swaggerSchemaDiscriminator :: Maybe Text+  , _swaggerSchemaReadOnly :: Maybe Bool+  , _swaggerSchemaXml :: Maybe SwaggerXml+  , _swaggerSchemaExternalDocs :: Maybe SwaggerExternalDocs+  , _swaggerSchemaExample :: Maybe Value -  , swaggerSchemaMaxProperties :: Maybe Integer-  , swaggerSchemaMinProperties :: Maybe Integer+  , _swaggerSchemaMaxProperties :: Maybe Integer+  , _swaggerSchemaMinProperties :: Maybe Integer -  , swaggerSchemaCommon :: SwaggerSchemaCommon+  , _swaggerSchemaCommon :: SwaggerSchemaCommon   } deriving (Eq, Show, Generic)  data SwaggerSchemaItems-  = SwaggerSchemaItemsObject SwaggerSchema-  | SwaggerSchemaItemsArray [SwaggerSchema]+  = SwaggerSchemaItemsObject (SwaggerReferenced SwaggerSchema)+  | SwaggerSchemaItemsArray [SwaggerReferenced SwaggerSchema]   deriving (Eq, Show)  data SwaggerSchemaCommon = SwaggerSchemaCommon@@ -418,20 +418,20 @@     -- if not supplied by the client in the request.     -- (Note: "default" has no meaning for required parameters.)     -- Unlike JSON Schema this value MUST conform to the defined type for this parameter.-    swaggerSchemaDefault :: Maybe Value+    _swaggerSchemaDefault :: Maybe Value -  , swaggerSchemaMaximum :: Maybe Integer-  , swaggerSchemaExclusiveMaximum :: Maybe Bool-  , swaggerSchemaMinimum :: Maybe Integer-  , swaggerSchemaExclusiveMinimum :: Maybe Bool-  , swaggerSchemaMaxLength :: Maybe Integer-  , swaggerSchemaMinLength :: Maybe Integer-  , swaggerSchemaPattern :: Maybe Text-  , swaggerSchemaMaxItems :: Maybe Integer-  , swaggerSchemaMinItems :: Maybe Integer-  , swaggerSchemaUniqueItems :: Maybe Bool-  , swaggerSchemaEnum :: Maybe [Value]-  , swaggerSchemaMultipleOf :: Maybe Integer+  , _swaggerSchemaMaximum :: Maybe Integer+  , _swaggerSchemaExclusiveMaximum :: Maybe Bool+  , _swaggerSchemaMinimum :: Maybe Integer+  , _swaggerSchemaExclusiveMinimum :: Maybe Bool+  , _swaggerSchemaMaxLength :: Maybe Integer+  , _swaggerSchemaMinLength :: Maybe Integer+  , _swaggerSchemaPattern :: Maybe Text+  , _swaggerSchemaMaxItems :: Maybe Integer+  , _swaggerSchemaMinItems :: Maybe Integer+  , _swaggerSchemaUniqueItems :: Maybe Bool+  , _swaggerSchemaEnum :: Maybe [Value]+  , _swaggerSchemaMultipleOf :: Maybe Integer   } deriving (Eq, Show, Generic)  data SwaggerXml = SwaggerXml@@ -440,18 +440,18 @@     -- When defined alongside type being array (outside the items),     -- it will affect the wrapping element and only if wrapped is true.     -- If wrapped is false, it will be ignored.-    swaggerXmlName :: Maybe Text+    _swaggerXmlName :: Maybe Text      -- | The URL of the namespace definition.     -- Value SHOULD be in the form of a URL.-  , swaggerXmlNamespace :: Maybe Text+  , _swaggerXmlNamespace :: Maybe Text      -- | The prefix to be used for the name.-  , swaggerXmlPrefix :: Maybe Text+  , _swaggerXmlPrefix :: Maybe Text      -- | Declares whether the property definition translates to an attribute instead of an element.     -- Default value is @False@.-  , swaggerXmlAttribute :: Bool+  , _swaggerXmlAttribute :: Bool      -- | MAY be used only for an array definition.     -- Signifies whether the array is wrapped@@ -459,25 +459,25 @@     -- or unwrapped (@\<book/\>\<book/\>@).     -- Default value is @False@.     -- The definition takes effect only when defined alongside type being array (outside the items).-  , swaggerXmlWrapped :: Bool-  } deriving (Eq, Show)+  , _swaggerXmlWrapped :: Bool+  } deriving (Eq, Show, Generic)  data SwaggerItems = SwaggerItems   { -- | The internal type of the array.-    swaggerItemsType :: SwaggerItemsType+    _swaggerItemsType :: SwaggerItemsType      -- | The extending format for the previously mentioned type.-  , swaggerItemsFormat :: SwaggerFormat+  , _swaggerItemsFormat :: Maybe SwaggerFormat      -- | __Required if type is @'SwaggerItemsArray'@.__     -- Describes the type of items in the array.-  , swaggerItemsItems :: SwaggerItems+  , _swaggerItemsItems :: Maybe SwaggerItems      -- | Determines the format of the array if type array is used.     -- Default value is @'SwaggerItemsCollectionCSV'@.-  , swaggerItemsCollectionFormat :: SwaggerItemsCollectionFormat+  , _swaggerItemsCollectionFormat :: Maybe SwaggerItemsCollectionFormat -  , swaggerItemsCommon :: SwaggerSchemaCommon+  , _swaggerItemsCommon :: SwaggerSchemaCommon   } deriving (Eq, Show, Generic)  -- | A container for the expected responses of an operation.@@ -488,11 +488,11 @@ data SwaggerResponses = SwaggerResponses   { -- | The documentation of responses other than the ones declared for specific HTTP response codes.     -- It can be used to cover undeclared responses.-    swaggerResponsesDefault :: Maybe SwaggerResponse+   _swaggerResponsesDefault :: Maybe (SwaggerReferenced SwaggerResponse)      -- | Any HTTP status code can be used as the property name (one property per HTTP status code).     -- Describes the expected response for those HTTP status codes.-  , swaggerResponsesResponses :: HashMap HttpStatusCode SwaggerResponse+  , _swaggerResponsesResponses :: HashMap HttpStatusCode (SwaggerReferenced SwaggerResponse)   } deriving (Eq, Show, Generic)  type HttpStatusCode = Int@@ -501,43 +501,43 @@ data SwaggerResponse = SwaggerResponse   { -- | A short description of the response.     -- GFM syntax can be used for rich text representation.-    swaggerResponseDescription :: Text+    _swaggerResponseDescription :: Text      -- | A definition of the response structure.     -- It can be a primitive, an array or an object.     -- If this field does not exist, it means no content is returned as part of the response.     -- As an extension to the Schema Object, its root type value may also be "file".     -- This SHOULD be accompanied by a relevant produces mime-type.-  , swaggerResponseSchema :: Maybe SwaggerSchema+  , _swaggerResponseSchema :: Maybe (SwaggerReferenced SwaggerSchema)      -- | A list of headers that are sent with the response.-  , swaggerResponseHeaders :: HashMap HeaderName SwaggerHeader+  , _swaggerResponseHeaders :: HashMap HeaderName SwaggerHeader      -- | An example of the response message.-  , swaggerResponseExamples :: Maybe SwaggerExample+  , _swaggerResponseExamples :: Maybe SwaggerExample   } deriving (Eq, Show, Generic)  type HeaderName = Text  data SwaggerHeader = SwaggerHeader   { -- | A short description of the header.-    swaggerHeaderDescription :: Maybe String+    _swaggerHeaderDescription :: Maybe Text      -- | The type of the object.-  , swaggerHeaderType :: SwaggerItemsType+  , _swaggerHeaderType :: SwaggerItemsType      -- | The extending format for the previously mentioned type. See Data Type Formats for further details.-  , swaggerHeaderFormat :: Maybe SwaggerFormat+  , _swaggerHeaderFormat :: Maybe SwaggerFormat      -- | __Required if type is @'SwaggerItemsArray'@__.     -- Describes the type of items in the array.-  , swaggerHeaderItems :: SwaggerItems+  , _swaggerHeaderItems :: Maybe SwaggerItems      -- | Determines the format of the array if type array is used.     -- Default value is @'SwaggerItemsCollectionCSV'@.-  , swaggerHeaderCollectionFormat :: SwaggerItemsCollectionFormat+  , _swaggerHeaderCollectionFormat :: Maybe SwaggerItemsCollectionFormat -  , swaggerHeaderCommon :: SwaggerSchemaCommon+  , _swaggerHeaderCommon :: SwaggerSchemaCommon   } deriving (Eq, Show, Generic)  data SwaggerExample = SwaggerExample { getSwaggerExample :: Map MediaType Value }@@ -551,10 +551,10 @@  data SwaggerApiKeyParams = SwaggerApiKeyParams   { -- | The name of the header or query parameter to be used.-    swaggerApiKeyName :: Text+    _swaggerApiKeyName :: Text      -- | The location of the API key.-  , swaggerApiKeyIn :: SwaggerApiKeyLocation+  , _swaggerApiKeyIn :: SwaggerApiKeyLocation   } deriving (Eq, Show)  -- | The authorization URL to be used for OAuth2 flow. This SHOULD be in the form of a URL.@@ -572,10 +572,10 @@  data SwaggerOAuth2Params = SwaggerOAuth2Params   { -- | The flow used by the OAuth2 security scheme.-    swaggerOAuth2Flow :: SwaggerOAuth2Flow+    _swaggerOAuth2Flow :: SwaggerOAuth2Flow      -- | The available scopes for the OAuth2 security scheme.-  , swaggerOAuth2Scopes :: HashMap Text Text+  , _swaggerOAuth2Scopes :: HashMap Text Text   } deriving (Eq, Show, Generic)  data SwaggerSecuritySchemeType@@ -586,10 +586,10 @@  data SwaggerSecurityScheme = SwaggerSecurityScheme   { -- | The type of the security scheme.-    swaggerSecuritySchemeType :: SwaggerSecuritySchemeType+    _swaggerSecuritySchemeType :: SwaggerSecuritySchemeType      -- | A short description for security scheme.-  , swaggerSecuritySchemeDescription :: Maybe Text+  , _swaggerSecuritySchemeDescription :: Maybe Text   } deriving (Eq, Show, Generic)  -- | Lists the required security schemes to execute this operation.@@ -603,26 +603,36 @@ -- It is not mandatory to have a @SwaggerTag@ per tag used there. data SwaggerTag = SwaggerTag   { -- | The name of the tag.-    swaggerTagName :: Text+    _swaggerTagName :: Text      -- | A short description for the tag.     -- GFM syntax can be used for rich text representation.-  , swaggerTagDescription :: Maybe Text+  , _swaggerTagDescription :: Maybe Text      -- | Additional external documentation for this tag.-  , swaggerTagExternalDocs :: Maybe SwaggerExternalDocs+  , _swaggerTagExternalDocs :: Maybe SwaggerExternalDocs   } deriving (Eq, Show)  -- | Allows referencing an external resource for extended documentation. data SwaggerExternalDocs = SwaggerExternalDocs   { -- | A short description of the target documentation.     -- GFM syntax can be used for rich text representation.-    swaggerExternalDocsDescription :: Maybe Text+    _swaggerExternalDocsDescription :: Maybe Text      -- | The URL for the target documentation.-  , swaggerExternalDocsUrl :: URL+  , _swaggerExternalDocsUrl :: URL   } deriving (Eq, Show, Generic) +-- | A simple object to allow referencing other definitions in the specification.+-- It can be used to reference parameters and responses that are defined at the top level for reuse.+newtype SwaggerReference = SwaggerReference { getSwaggerReference :: Text }+  deriving (Eq, Show)++data SwaggerReferenced a+  = SwaggerRef SwaggerReference+  | SwaggerInline a+  deriving (Eq, Show)+ newtype URL = URL { getUrl :: Text } deriving (Eq, Show, ToJSON, FromJSON)  -- =======================================================================@@ -712,6 +722,15 @@   swaggerMempty = HashMap.empty   swaggerMappend = HashMap.unionWith mappend +instance SwaggerMonoid (HashMap Text (SwaggerReferenced SwaggerSchema)) where+  swaggerMempty = HashMap.empty+  swaggerMappend = HashMap.unionWith swaggerMappend++instance Monoid a => SwaggerMonoid (SwaggerReferenced a) where+  swaggerMempty = SwaggerInline mempty+  swaggerMappend (SwaggerInline x) (SwaggerInline y) = SwaggerInline (x <> y)+  swaggerMappend _ y = y+ instance SwaggerMonoid (HashMap Text SwaggerParameter) where   swaggerMempty = HashMap.empty   swaggerMappend = HashMap.unionWith mappend@@ -732,7 +751,7 @@   swaggerMempty = HashMap.empty   swaggerMappend = flip HashMap.union -instance SwaggerMonoid (HashMap HttpStatusCode SwaggerResponse) where+instance SwaggerMonoid (HashMap HttpStatusCode (SwaggerReferenced SwaggerResponse)) where   swaggerMempty = HashMap.empty   swaggerMappend = flip HashMap.union @@ -761,11 +780,11 @@ deriveJSONDefault ''SwaggerScheme deriveJSON' ''SwaggerTag deriveJSON' ''SwaggerExternalDocs-deriveJSON' ''SwaggerXml  deriveToJSON' ''SwaggerOperation deriveToJSON' ''SwaggerResponse deriveToJSON' ''SwaggerPathItem+deriveToJSON' ''SwaggerXml  -- ======================================================================= -- Manual ToJSON instances@@ -833,7 +852,7 @@   toJSON = genericToJSONWithSub "schema" (jsonPrefix "swaggerParameter")  instance ToJSON SwaggerParameterSchema where-  toJSON (SwaggerParameterBody s) = toJSON s <+> object [ "in" .= ("body" :: Text) ]+  toJSON (SwaggerParameterBody s) = object [ "in" .= ("body" :: Text), "schema" .= s ]   toJSON (SwaggerParameterOther s) = toJSON s  instance ToJSON SwaggerParameterOtherSchema where@@ -849,6 +868,13 @@ instance ToJSON SwaggerExample where   toJSON = toJSON . Map.mapKeys show . getSwaggerExample +instance ToJSON SwaggerReference where+  toJSON (SwaggerReference ref) = object [ "$ref" .= ref ]++instance ToJSON a => ToJSON (SwaggerReferenced a) where+  toJSON (SwaggerRef ref) = toJSON ref+  toJSON (SwaggerInline x) = toJSON x+ -- ======================================================================= -- Manual FromJSON instances -- =======================================================================@@ -912,10 +938,10 @@ instance FromJSON SwaggerHost where   parseJSON (String s) =     case fromInteger <$> readMaybe portStr of-      Nothing | not (null portStr) -> empty+      Nothing | not (null portStr) -> fail $ "Invalid port `" ++ portStr ++ "'"       mport -> pure $ SwaggerHost host mport     where-      (hostText, portText) = Text.breakOnEnd ":" s+      (hostText, portText) = Text.breakOn ":" s       [host, portStr] = map Text.unpack [hostText, portText]   parseJSON _ = empty @@ -933,7 +959,9 @@   parseJSON json@(Object o) = do     (i :: Text) <- o .: "in"     case i of-      "body" -> SwaggerParameterBody <$> parseJSON json+      "body" -> do+        schema <- o .: "schema"+        SwaggerParameterBody <$> parseJSON schema       _ -> SwaggerParameterOther <$> parseJSON json   parseJSON _ = empty @@ -969,4 +997,17 @@ instance FromJSON SwaggerPathItem where   parseJSON = genericParseJSON (jsonPrefix "swaggerPathItem")     `withDefaults` [ "parameters" .= ([] :: [SwaggerParameter]) ]++instance FromJSON SwaggerReference where+  parseJSON (Object o) = SwaggerReference <$> o .: "$ref"+  parseJSON _ = empty++instance FromJSON a => FromJSON (SwaggerReferenced a) where+  parseJSON json+      = SwaggerRef    <$> parseJSON json+    <|> SwaggerInline <$> parseJSON json++instance FromJSON SwaggerXml where+  parseJSON = genericParseJSON (jsonPrefix "swaggerXml")+    `withDefaults` [ "attribute" .= False, "wrapped" .= False ] 
src/Data/Swagger/Internal/Utils.hs view
@@ -32,7 +32,7 @@  jsonPrefix :: String -> Options jsonPrefix prefix = defaultOptions-  { fieldLabelModifier      = modifier+  { fieldLabelModifier      = modifier . drop 1   , constructorTagModifier  = modifier   , sumEncoding             = ObjectWithSingleField   }
+ src/Data/Swagger/Lens.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+module Data.Swagger.Lens where++import Control.Lens+import Control.Lens.TH+import Data.Aeson (Value)+import Data.Swagger.Internal+import Data.Text (Text)++-- =======================================================================+-- TH derived lenses+-- =======================================================================++makeLenses ''Swagger+makeLenses ''SwaggerHost+makeLenses ''SwaggerInfo+makeLenses ''SwaggerContact+makeLenses ''SwaggerLicense+makeLenses ''SwaggerPaths+makeLenses ''SwaggerPathItem+makeLenses ''SwaggerTag+makeLenses ''SwaggerOperation+makeLenses ''SwaggerParameter+makePrisms ''SwaggerParameterSchema+makeLenses ''SwaggerParameterOtherSchema+makeLenses ''SwaggerItems+makeLenses ''SwaggerHeader+makeLenses ''SwaggerSchema+makePrisms ''SwaggerSchemaItems+makeLenses ''SwaggerSchemaCommon+makeLenses ''SwaggerXml+makeLenses ''SwaggerResponses+makeLenses ''SwaggerResponse+makeLenses ''SwaggerSecurityScheme+makePrisms ''SwaggerSecuritySchemeType+makeLenses ''SwaggerApiKeyParams+makeLenses ''SwaggerOAuth2Params+makeLenses ''SwaggerExternalDocs++-- =======================================================================+-- Helper classy lenses+-- =======================================================================++class HasDescription s d | s -> d where+  description :: Lens' s d++instance HasDescription SwaggerResponse       Text where description = swaggerResponseDescription+instance HasDescription SwaggerInfo           (Maybe Text) where description = swaggerInfoDescription+instance HasDescription SwaggerTag            (Maybe Text) where description = swaggerTagDescription+instance HasDescription SwaggerOperation      (Maybe Text) where description = swaggerOperationDescription+instance HasDescription SwaggerParameter      (Maybe Text) where description = swaggerParameterDescription+instance HasDescription SwaggerHeader         (Maybe Text) where description = swaggerHeaderDescription+instance HasDescription SwaggerSchema         (Maybe Text) where description = swaggerSchemaDescription+instance HasDescription SwaggerSecurityScheme (Maybe Text) where description = swaggerSecuritySchemeDescription+instance HasDescription SwaggerExternalDocs   (Maybe Text) where description = swaggerExternalDocsDescription++class HasSwaggerSchemaCommon s where+  schemaCommon :: Lens' s SwaggerSchemaCommon++instance HasSwaggerSchemaCommon SwaggerSchema where schemaCommon = swaggerSchemaCommon+instance HasSwaggerSchemaCommon SwaggerParameterOtherSchema where schemaCommon = swaggerParameterOtherSchemaCommon+instance HasSwaggerSchemaCommon SwaggerItems where schemaCommon = swaggerItemsCommon+instance HasSwaggerSchemaCommon SwaggerHeader where schemaCommon = swaggerHeaderCommon+instance HasSwaggerSchemaCommon SwaggerSchemaCommon where schemaCommon = id++schemaDefault :: HasSwaggerSchemaCommon s => Lens' s (Maybe Value)+schemaDefault = schemaCommon.swaggerSchemaDefault++schemaMaximum :: HasSwaggerSchemaCommon s => Lens' s (Maybe Integer)+schemaMaximum = schemaCommon.swaggerSchemaMaximum++schemaExclusiveMaximum :: HasSwaggerSchemaCommon s => Lens' s (Maybe Bool)+schemaExclusiveMaximum = schemaCommon.swaggerSchemaExclusiveMaximum++schemaMinimum :: HasSwaggerSchemaCommon s => Lens' s (Maybe Integer)+schemaMinimum = schemaCommon.swaggerSchemaMinimum++schemaExclusiveMinimum :: HasSwaggerSchemaCommon s => Lens' s (Maybe Bool)+schemaExclusiveMinimum = schemaCommon.swaggerSchemaExclusiveMinimum++schemaMaxLength :: HasSwaggerSchemaCommon s => Lens' s (Maybe Integer)+schemaMaxLength = schemaCommon.swaggerSchemaMaxLength++schemaMinLength :: HasSwaggerSchemaCommon s => Lens' s (Maybe Integer)+schemaMinLength = schemaCommon.swaggerSchemaMinLength++schemaPattern :: HasSwaggerSchemaCommon s => Lens' s (Maybe Text)+schemaPattern = schemaCommon.swaggerSchemaPattern++schemaMaxItems :: HasSwaggerSchemaCommon s => Lens' s (Maybe Integer)+schemaMaxItems = schemaCommon.swaggerSchemaMaxItems++schemaMinItems :: HasSwaggerSchemaCommon s => Lens' s (Maybe Integer)+schemaMinItems = schemaCommon.swaggerSchemaMinItems++schemaUniqueItems :: HasSwaggerSchemaCommon s => Lens' s (Maybe Bool)+schemaUniqueItems = schemaCommon.swaggerSchemaUniqueItems++schemaEnum :: HasSwaggerSchemaCommon s => Lens' s (Maybe [Value])+schemaEnum = schemaCommon.swaggerSchemaEnum++schemaMultipleOf :: HasSwaggerSchemaCommon s => Lens' s (Maybe Integer)+schemaMultipleOf = schemaCommon.swaggerSchemaMultipleOf+
swagger2.cabal view
@@ -1,5 +1,5 @@ name:                swagger2-version:             0.1+version:             0.2 synopsis:            Swagger 2.0 data model description:         Please see README.md homepage:            https://github.com/GetShopTV/swagger2@@ -12,12 +12,16 @@ build-type:          Simple extra-source-files:     README.md+  , CHANGELOG.md cabal-version:       >=1.10  library   hs-source-dirs:      src   exposed-modules:     Data.Swagger+    Data.Swagger.Lens++    -- internal modules     Data.Swagger.Internal     Data.Swagger.Internal.Utils   build-depends:       base == 4.*@@ -29,6 +33,7 @@                      , template-haskell                      , text                      , unordered-containers+                     , lens   default-language:    Haskell2010  test-suite spec
test/Data/SwaggerSpec.hs view
@@ -1,612 +1,1659 @@ {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-module Data.SwaggerSpec where--import Data.Aeson-import Data.Aeson.QQ-import qualified Data.Foldable as F-import Data.HashMap.Strict (HashMap)-import qualified Data.HashMap.Strict as HashMap-import Data.Maybe-import Data.Monoid-import qualified Data.Vector as Vector-import Data.Text (Text)--import Data.Swagger--import Test.Hspec--isSubJSON :: Value -> Value -> Bool-isSubJSON Null _ = True-isSubJSON (Object x) (Object y) = HashMap.keys x == HashMap.keys i && F.and i-  where-    i = HashMap.intersectionWith isSubJSON x y-isSubJSON (Array xs) (Array ys) = Vector.length xs == Vector.length ys && F.and (Vector.zipWith isSubJSON xs ys)-isSubJSON x y = x == y--(<~>) :: (Eq a, Show a, ToJSON a, FromJSON a) => a -> Value -> Spec-x <~> json = do-  it "encodes correctly (probably with extra properties)" $ do-    toJSON x `shouldSatisfy` (json `isSubJSON`)-  it "decodes correctly" $ do-    fromJSON json `shouldBe` Success x--(<=>) :: (Eq a, Show a, ToJSON a, FromJSON a) => a -> Value -> Spec-x <=> json = do-  it "encodes correctly" $ do-    toJSON x `shouldBe` json-  it "decodes correctly" $ do-    fromJSON json `shouldBe` Success x--spec :: Spec-spec = do-  describe "License Object" $ licenseExample <=> licenseExampleJSON-  describe "Contact Object" $ contactExample <=> contactExampleJSON-  describe "Info Object" $ infoExample <=> infoExampleJSON-  describe "Operation Object" $ operationExample <~> operationExampleJSON-  describe "Schema Object" $ do-    context "Primitive Sample" $ schemaPrimitiveExample <~> schemaPrimitiveExampleJSON-    context "Simple Model" $ schemaSimpleModelExample <~> schemaSimpleModelExampleJSON-    context "Model with Map/Dictionary Properties" $ schemaModelDictExample <~> schemaModelDictExampleJSON-    context "Model with Example" $ schemaWithExampleExample <~> schemaWithExampleExampleJSON-  describe "Definitions Object" $ definitionsExample <~> definitionsExampleJSON-  describe "Parameters Definition Object" $ parametersDefinitionExample <~> parametersDefinitionExampleJSON-  describe "Responses Definition Object" $ responsesDefinitionExample <~> responsesDefinitionExampleJSON-  describe "Security Definitions Object" $ securityDefinitionsExample <~> securityDefinitionsExampleJSON-  describe "Swagger Object" $ swaggerExample <~> swaggerExampleJSON--main :: IO ()-main = hspec spec---- =======================================================================--- Info object--- =======================================================================--infoExample :: SwaggerInfo-infoExample = SwaggerInfo-  { swaggerInfoTitle = "Swagger Sample App"-  , swaggerInfoDescription = Just "This is a sample server Petstore server."-  , swaggerInfoTermsOfService = Just "http://swagger.io/terms/"-  , swaggerInfoContact = Just contactExample-  , swaggerInfoLicense = Just licenseExample-  , swaggerInfoVersion = "1.0.1" }-  where-    license = SwaggerLicense-      { swaggerLicenseName = "Apache 2.0"-      , swaggerLicenseUrl = Just (URL "http://www.apache.org/licenses/LICENSE-2.0.html") }--infoExampleJSON :: Value-infoExampleJSON = [aesonQQ|-{-  "title": "Swagger Sample App",-  "description": "This is a sample server Petstore server.",-  "termsOfService": "http://swagger.io/terms/",-  "contact": {-    "name": "API Support",-    "url": "http://www.swagger.io/support",-    "email": "support@swagger.io"-  },-  "license": {-    "name": "Apache 2.0",-    "url": "http://www.apache.org/licenses/LICENSE-2.0.html"-  },-  "version": "1.0.1"-}-|]---- =======================================================================--- Contact object--- =======================================================================--contactExample :: SwaggerContact-contactExample = SwaggerContact-  { swaggerContactName = Just "API Support"-  , swaggerContactUrl = Just (URL "http://www.swagger.io/support")-  , swaggerContactEmail = Just "support@swagger.io" }--contactExampleJSON :: Value-contactExampleJSON = [aesonQQ|-{-  "name": "API Support",-  "url": "http://www.swagger.io/support",-  "email": "support@swagger.io"-}-|]---- =======================================================================--- License object--- =======================================================================--licenseExample :: SwaggerLicense-licenseExample = SwaggerLicense-  { swaggerLicenseName = "Apache 2.0"-  , swaggerLicenseUrl = Just (URL "http://www.apache.org/licenses/LICENSE-2.0.html") }--licenseExampleJSON :: Value-licenseExampleJSON = [aesonQQ|-{-  "name": "Apache 2.0",-  "url": "http://www.apache.org/licenses/LICENSE-2.0.html"-}-|]----- =======================================================================--- Operation object--- =======================================================================--operationExample :: SwaggerOperation-operationExample = mempty-  { swaggerOperationTags = ["pet"]-  , swaggerOperationSummary = Just "Updates a pet in the store with form data"-  , swaggerOperationDescription = Just ""-  , swaggerOperationOperationId = Just "updatePetWithForm"-  , swaggerOperationConsumes = Just (SwaggerMimeList ["application/x-www-form-urlencoded"])-  , swaggerOperationProduces = Just (SwaggerMimeList ["application/json", "application/xml"])-  , swaggerOperationParameters = params-  , swaggerOperationResponses = responses-  , swaggerOperationSecurity = security-  }-  where-    security = [SwaggerSecurityRequirement [("petstore_auth", ["write:pets", "read:pets"])]]--    responses = mempty-      { swaggerResponsesResponses =-          [ (200, mempty { swaggerResponseDescription = "Pet updated." })-          , (405, mempty { swaggerResponseDescription = "Invalid input" }) ] }--    params =-      [ SwaggerParameter-          { swaggerParameterName = "petId"-          , swaggerParameterDescription = Just "ID of pet that needs to be updated"-          , swaggerParameterRequired = True-          , swaggerParameterSchema = SwaggerParameterOther (stringSchema SwaggerParameterPath) }-      , SwaggerParameter-          { swaggerParameterName = "name"-          , swaggerParameterDescription = Just "Updated name of the pet"-          , swaggerParameterRequired = False-          , swaggerParameterSchema = SwaggerParameterOther (stringSchema SwaggerParameterFormData) }-      , SwaggerParameter-          { swaggerParameterName = "status"-          , swaggerParameterDescription = Just "Updated status of the pet"-          , swaggerParameterRequired = False-          , swaggerParameterSchema = SwaggerParameterOther (stringSchema SwaggerParameterFormData) }-      ]--    stringSchema i = mempty-      { swaggerParameterOtherSchemaIn = i-      , swaggerParameterOtherSchemaType = SwaggerParamString-      }--operationExampleJSON :: Value-operationExampleJSON = [aesonQQ|-{-  "tags": [-    "pet"-  ],-  "summary": "Updates a pet in the store with form data",-  "description": "",-  "operationId": "updatePetWithForm",-  "consumes": [-    "application/x-www-form-urlencoded"-  ],-  "produces": [-    "application/json",-    "application/xml"-  ],-  "parameters": [-    {-      "name": "petId",-      "in": "path",-      "description": "ID of pet that needs to be updated",-      "required": true,-      "type": "string"-    },-    {-      "name": "name",-      "in": "formData",-      "description": "Updated name of the pet",-      "required": false,-      "type": "string"-    },-    {-      "name": "status",-      "in": "formData",-      "description": "Updated status of the pet",-      "required": false,-      "type": "string"-    }-  ],-  "responses": {-    "200": {-      "description": "Pet updated."-    },-    "405": {-      "description": "Invalid input"-    }-  },-  "security": [-    {-      "petstore_auth": [-        "write:pets",-        "read:pets"-      ]-    }-  ]-}-|]---- =======================================================================--- Schema object--- =======================================================================--schemaPrimitiveExample :: SwaggerSchema-schemaPrimitiveExample = mempty-  { swaggerSchemaType = SwaggerSchemaString-  , swaggerSchemaFormat = Just "email"-  }--schemaPrimitiveExampleJSON :: Value-schemaPrimitiveExampleJSON = [aesonQQ|-{-    "type": "string",-    "format": "email"-}-|]--schemaSimpleModelExample :: SwaggerSchema-schemaSimpleModelExample = mempty-  { swaggerSchemaType = SwaggerSchemaObject-  , swaggerSchemaRequired = [ "name" ]-  , swaggerSchemaProperties =-      [ ("name", mempty-            { swaggerSchemaType = SwaggerSchemaString } )-      , ("age", mempty-            { swaggerSchemaType = SwaggerSchemaInteger-            , swaggerSchemaFormat = Just "int32"-            , swaggerSchemaCommon = mempty-                { swaggerSchemaMinimum = Just 0 } } ) ] }--schemaSimpleModelExampleJSON :: Value-schemaSimpleModelExampleJSON = [aesonQQ|-{-  "type": "object",-  "required": [-    "name"-  ],-  "properties": {-    "name": {-      "type": "string"-    },-    "age": {-      "type": "integer",-      "format": "int32",-      "minimum": 0-    }-  }-}-|]--schemaModelDictExample :: SwaggerSchema-schemaModelDictExample = mempty-  { swaggerSchemaType = SwaggerSchemaObject-  , swaggerSchemaAdditionalProperties = Just mempty-      { swaggerSchemaType = SwaggerSchemaString } }--schemaModelDictExampleJSON :: Value-schemaModelDictExampleJSON = [aesonQQ|-{-  "type": "object",-  "additionalProperties": {-    "type": "string"-  }-}-|]--schemaWithExampleExample :: SwaggerSchema-schemaWithExampleExample = mempty-  { swaggerSchemaType = SwaggerSchemaObject-  , swaggerSchemaProperties =-      [ ("id", mempty-            { swaggerSchemaType   = SwaggerSchemaInteger-            , swaggerSchemaFormat = Just "int64" })-      , ("name", mempty-            { swaggerSchemaType = SwaggerSchemaString }) ]-  , swaggerSchemaRequired = [ "name" ]-  , swaggerSchemaExample = Just [aesonQQ|-      {-        "name": "Puma",-        "id": 1-      }-    |] }--schemaWithExampleExampleJSON :: Value-schemaWithExampleExampleJSON = [aesonQQ|-{-  "type": "object",-  "properties": {-    "id": {-      "type": "integer",-      "format": "int64"-    },-    "name": {-      "type": "string"-    }-  },-  "required": [-    "name"-  ],-  "example": {-    "name": "Puma",-    "id": 1-  }-}-|]---- =======================================================================--- Definitions object--- =======================================================================--definitionsExample :: HashMap Text SwaggerSchema-definitionsExample =-  [ ("Category", mempty-      { swaggerSchemaType = SwaggerSchemaObject-      , swaggerSchemaProperties =-          [ ("id", mempty-              { swaggerSchemaType = SwaggerSchemaInteger-              , swaggerSchemaFormat = Just "int64" })-          , ("name", mempty-              { swaggerSchemaType = SwaggerSchemaString }) ] })-  , ("Tag", mempty-      { swaggerSchemaType = SwaggerSchemaObject-      , swaggerSchemaProperties =-          [ ("id", mempty-              { swaggerSchemaType = SwaggerSchemaInteger-              , swaggerSchemaFormat = Just "int64" })-          , ("name", mempty-              { swaggerSchemaType = SwaggerSchemaString }) ] }) ]--definitionsExampleJSON :: Value-definitionsExampleJSON = [aesonQQ|-{-  "Category": {-    "type": "object",-    "properties": {-      "id": {-        "type": "integer",-        "format": "int64"-      },-      "name": {-        "type": "string"-      }-    }-  },-  "Tag": {-    "type": "object",-    "properties": {-      "id": {-        "type": "integer",-        "format": "int64"-      },-      "name": {-        "type": "string"-      }-    }-  }-}-|]---- =======================================================================--- Parameters Definition object--- =======================================================================--parametersDefinitionExample :: HashMap Text SwaggerParameter-parametersDefinitionExample =-  [ ("skipParam", mempty-      { swaggerParameterName = "skip"-      , swaggerParameterDescription = Just "number of items to skip"-      , swaggerParameterRequired = True-      , swaggerParameterSchema = SwaggerParameterOther mempty-          { swaggerParameterOtherSchemaIn = SwaggerParameterQuery-          , swaggerParameterOtherSchemaType = SwaggerParamInteger-          , swaggerParameterOtherSchemaFormat = Just "int32" } })-  , ("limitParam", mempty-      { swaggerParameterName = "limit"-      , swaggerParameterDescription = Just "max records to return"-      , swaggerParameterRequired = True-      , swaggerParameterSchema = SwaggerParameterOther mempty-          { swaggerParameterOtherSchemaIn = SwaggerParameterQuery-          , swaggerParameterOtherSchemaType = SwaggerParamInteger-          , swaggerParameterOtherSchemaFormat = Just "int32" } }) ]--parametersDefinitionExampleJSON :: Value-parametersDefinitionExampleJSON = [aesonQQ|-{-  "skipParam": {-    "name": "skip",-    "in": "query",-    "description": "number of items to skip",-    "required": true,-    "type": "integer",-    "format": "int32"-  },-  "limitParam": {-    "name": "limit",-    "in": "query",-    "description": "max records to return",-    "required": true,-    "type": "integer",-    "format": "int32"-  }-}-|]---- =======================================================================--- Responses Definition object--- =======================================================================--responsesDefinitionExample :: HashMap Text SwaggerResponse-responsesDefinitionExample =-  [ ("NotFound", mempty { swaggerResponseDescription = "Entity not found." })-  , ("IllegalInput", mempty { swaggerResponseDescription = "Illegal input for operation." }) ]--responsesDefinitionExampleJSON :: Value-responsesDefinitionExampleJSON = [aesonQQ|-{-  "NotFound": {-    "description": "Entity not found."-  },-  "IllegalInput": {-    "description": "Illegal input for operation."-  }-}-|]---- =======================================================================--- Responses Definition object--- =======================================================================--securityDefinitionsExample :: HashMap Text SwaggerSecurityScheme-securityDefinitionsExample =-  [ ("api_key", SwaggerSecurityScheme-      { swaggerSecuritySchemeType = SwaggerSecuritySchemeApiKey (SwaggerApiKeyParams "api_key" SwaggerApiKeyHeader)-      , swaggerSecuritySchemeDescription = Nothing })-  , ("petstore_auth", SwaggerSecurityScheme-      { swaggerSecuritySchemeType = SwaggerSecuritySchemeOAuth2 (SwaggerOAuth2Params-          { swaggerOAuth2Flow = SwaggerOAuth2Implicit "http://swagger.io/api/oauth/dialog"-          , swaggerOAuth2Scopes =-              [ ("write:pets",  "modify pets in your account")-              , ("read:pets", "read your pets") ] } )-      , swaggerSecuritySchemeDescription = Nothing }) ]--securityDefinitionsExampleJSON :: Value-securityDefinitionsExampleJSON = [aesonQQ|-{-  "api_key": {-    "type": "apiKey",-    "name": "api_key",-    "in": "header"-  },-  "petstore_auth": {-    "type": "oauth2",-    "authorizationUrl": "http://swagger.io/api/oauth/dialog",-    "flow": "implicit",-    "scopes": {-      "write:pets": "modify pets in your account",-      "read:pets": "read your pets"-    }-  }-}-|]---- =======================================================================--- Swagger object--- =======================================================================--swaggerExample :: Swagger-swaggerExample = mempty-  { swaggerBasePath = Just "/"-  , swaggerSchemes = Just [Http]-  , swaggerInfo = mempty-      { swaggerInfoVersion = "1.0"-      , swaggerInfoTitle = "Todo API"-      , swaggerInfoLicense = Just SwaggerLicense-          { swaggerLicenseName = "MIT"-          , swaggerLicenseUrl = Just (URL "http://mit.com") }-      , swaggerInfoDescription = Just "This is a an API that tests servant-swagger support for a Todo API" }-  , swaggerPaths = mempty-      { swaggerPathsMap =-          [ ("/todo/{id}", mempty-              { swaggerPathItemGet = Just mempty-                  { swaggerOperationResponses = mempty-                      { swaggerResponsesResponses =-                          [ (200, mempty-                              { swaggerResponseSchema = Just mempty-                                { swaggerSchemaExample = Just [aesonQQ|-                                    {-                                      "created": 100,-                                      "description": "get milk"-                                    } |]-                                , swaggerSchemaType = SwaggerSchemaObject-                                , swaggerSchemaDescription = Just "This is some real Todo right here"-                                , swaggerSchemaProperties =-                                    [ ("created", mempty-                                        { swaggerSchemaType = SwaggerSchemaInteger-                                        , swaggerSchemaFormat = Just "int32" })-                                    , ("description", mempty-                                        { swaggerSchemaType = SwaggerSchemaString }) ] }-                              , swaggerResponseDescription = "OK" }) ] }-                  , swaggerOperationProduces = Just (SwaggerMimeList [ "application/json" ])-                  , swaggerOperationParameters =-                      [ mempty-                          { swaggerParameterRequired = True-                          , swaggerParameterName = "id"-                          , swaggerParameterDescription = Just "TodoId param"-                          , swaggerParameterSchema = SwaggerParameterOther mempty-                              { swaggerParameterOtherSchemaIn = SwaggerParameterPath-                              , swaggerParameterOtherSchemaType = SwaggerParamString } } ]-                  , swaggerOperationTags = [ "todo" ] } }) ] } }--swaggerExampleJSON :: Value-swaggerExampleJSON = [aesonQQ|-{-    "swagger": "2.0",-    "basePath": "/",-    "schemes": [-        "http"-    ],-    "info": {-        "version": "1.0",-        "title": "Todo API",-        "license": {-            "url": "http://mit.com",-            "name": "MIT"-        },-        "description": "This is a an API that tests servant-swagger support for a Todo API"-    },-    "paths": {-        "/todo/{id}": {-            "get": {-                "responses": {-                    "200": {-                        "schema": {-                            "example": {-                                "created": 100,-                                "description": "get milk"-                            },-                            "type": "object",-                            "description": "This is some real Todo right here",-                            "properties": {-                                "created": {-                                    "format": "int32",-                                    "type": "integer"-                                },-                                "description": {-                                    "type": "string"-                                }-                            }-                        },-                        "description": "OK"-                    }-                },-                "produces": [-                    "application/json"-                ],-                "parameters": [-                    {-                        "required": true,-                        "in": "path",-                        "name": "id",-                        "type": "string",-                        "description": "TodoId param"-                    }-                ],-                "tags": [-                    "todo"-                ]-            }-        }-    }+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE QuasiQuotes #-}+module Data.SwaggerSpec where++import Data.Aeson+import Data.Aeson.QQ+import qualified Data.Foldable as F+import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap+import Data.Maybe+import Data.Monoid+import qualified Data.Vector as Vector+import Data.Text (Text)++import Data.Swagger++import Test.Hspec++isSubJSON :: Value -> Value -> Bool+isSubJSON Null _ = True+isSubJSON (Object x) (Object y) = HashMap.keys x == HashMap.keys i && F.and i+  where+    i = HashMap.intersectionWith isSubJSON x y+isSubJSON (Array xs) (Array ys) = Vector.length xs == Vector.length ys && F.and (Vector.zipWith isSubJSON xs ys)+isSubJSON x y = x == y++(<~>) :: (Eq a, Show a, ToJSON a, FromJSON a) => a -> Value -> Spec+x <~> json = do+  it "encodes correctly (probably with extra properties)" $ do+    toJSON x `shouldSatisfy` (json `isSubJSON`)+  it "decodes correctly" $ do+    fromJSON json `shouldBe` Success x++(<=>) :: (Eq a, Show a, ToJSON a, FromJSON a) => a -> Value -> Spec+x <=> json = do+  it "encodes correctly" $ do+    toJSON x `shouldBe` json+  it "decodes correctly" $ do+    fromJSON json `shouldBe` Success x++spec :: Spec+spec = do+  describe "License Object" $ licenseExample <=> licenseExampleJSON+  describe "Contact Object" $ contactExample <=> contactExampleJSON+  describe "Info Object" $ infoExample <=> infoExampleJSON+  describe "Operation Object" $ operationExample <~> operationExampleJSON+  describe "Schema Object" $ do+    context "Primitive Sample" $ schemaPrimitiveExample <~> schemaPrimitiveExampleJSON+    context "Simple Model" $ schemaSimpleModelExample <~> schemaSimpleModelExampleJSON+    context "Model with Map/Dictionary Properties" $ schemaModelDictExample <~> schemaModelDictExampleJSON+    context "Model with Example" $ schemaWithExampleExample <~> schemaWithExampleExampleJSON+  describe "Definitions Object" $ definitionsExample <~> definitionsExampleJSON+  describe "Parameters Definition Object" $ parametersDefinitionExample <~> parametersDefinitionExampleJSON+  describe "Responses Definition Object" $ responsesDefinitionExample <~> responsesDefinitionExampleJSON+  describe "Security Definitions Object" $ securityDefinitionsExample <~> securityDefinitionsExampleJSON+  describe "Swagger Object" $ do+    context "Todo Example" $ swaggerExample <~> swaggerExampleJSON+    context "PetStore Example" $+      it "decodes successfully" $ do+        fromJSON petstoreExampleJSON `shouldSatisfy` (\x -> case x of Success (_ :: Swagger) -> True; _ -> False)++main :: IO ()+main = hspec spec++-- =======================================================================+-- Info object+-- =======================================================================++infoExample :: SwaggerInfo+infoExample = SwaggerInfo+  { _swaggerInfoTitle = "Swagger Sample App"+  , _swaggerInfoDescription = Just "This is a sample server Petstore server."+  , _swaggerInfoTermsOfService = Just "http://swagger.io/terms/"+  , _swaggerInfoContact = Just contactExample+  , _swaggerInfoLicense = Just licenseExample+  , _swaggerInfoVersion = "1.0.1" }+  where+    license = SwaggerLicense+      { _swaggerLicenseName = "Apache 2.0"+      , _swaggerLicenseUrl = Just (URL "http://www.apache.org/licenses/LICENSE-2.0.html") }++infoExampleJSON :: Value+infoExampleJSON = [aesonQQ|+{+  "title": "Swagger Sample App",+  "description": "This is a sample server Petstore server.",+  "termsOfService": "http://swagger.io/terms/",+  "contact": {+    "name": "API Support",+    "url": "http://www.swagger.io/support",+    "email": "support@swagger.io"+  },+  "license": {+    "name": "Apache 2.0",+    "url": "http://www.apache.org/licenses/LICENSE-2.0.html"+  },+  "version": "1.0.1"+}+|]++-- =======================================================================+-- Contact object+-- =======================================================================++contactExample :: SwaggerContact+contactExample = SwaggerContact+  { _swaggerContactName = Just "API Support"+  , _swaggerContactUrl = Just (URL "http://www.swagger.io/support")+  , _swaggerContactEmail = Just "support@swagger.io" }++contactExampleJSON :: Value+contactExampleJSON = [aesonQQ|+{+  "name": "API Support",+  "url": "http://www.swagger.io/support",+  "email": "support@swagger.io"+}+|]++-- =======================================================================+-- License object+-- =======================================================================++licenseExample :: SwaggerLicense+licenseExample = SwaggerLicense+  { _swaggerLicenseName = "Apache 2.0"+  , _swaggerLicenseUrl = Just (URL "http://www.apache.org/licenses/LICENSE-2.0.html") }++licenseExampleJSON :: Value+licenseExampleJSON = [aesonQQ|+{+  "name": "Apache 2.0",+  "url": "http://www.apache.org/licenses/LICENSE-2.0.html"+}+|]+++-- =======================================================================+-- Operation object+-- =======================================================================++operationExample :: SwaggerOperation+operationExample = mempty+  { _swaggerOperationTags = ["pet"]+  , _swaggerOperationSummary = Just "Updates a pet in the store with form data"+  , _swaggerOperationDescription = Just ""+  , _swaggerOperationOperationId = Just "updatePetWithForm"+  , _swaggerOperationConsumes = Just (SwaggerMimeList ["application/x-www-form-urlencoded"])+  , _swaggerOperationProduces = Just (SwaggerMimeList ["application/json", "application/xml"])+  , _swaggerOperationParameters = params+  , _swaggerOperationResponses = responses+  , _swaggerOperationSecurity = security+  }+  where+    security = [SwaggerSecurityRequirement [("petstore_auth", ["write:pets", "read:pets"])]]++    responses = mempty+      { _swaggerResponsesResponses =+          [ (200, SwaggerInline mempty { _swaggerResponseDescription = "Pet updated." })+          , (405, SwaggerInline mempty { _swaggerResponseDescription = "Invalid input" }) ] }++    params = map SwaggerInline+      [ SwaggerParameter+          { _swaggerParameterName = "petId"+          , _swaggerParameterDescription = Just "ID of pet that needs to be updated"+          , _swaggerParameterRequired = True+          , _swaggerParameterSchema = SwaggerParameterOther (stringSchema SwaggerParameterPath) }+      , SwaggerParameter+          { _swaggerParameterName = "name"+          , _swaggerParameterDescription = Just "Updated name of the pet"+          , _swaggerParameterRequired = False+          , _swaggerParameterSchema = SwaggerParameterOther (stringSchema SwaggerParameterFormData) }+      , SwaggerParameter+          { _swaggerParameterName = "status"+          , _swaggerParameterDescription = Just "Updated status of the pet"+          , _swaggerParameterRequired = False+          , _swaggerParameterSchema = SwaggerParameterOther (stringSchema SwaggerParameterFormData) }+      ]++    stringSchema i = mempty+      { _swaggerParameterOtherSchemaIn = i+      , _swaggerParameterOtherSchemaType = SwaggerParamString+      }++operationExampleJSON :: Value+operationExampleJSON = [aesonQQ|+{+  "tags": [+    "pet"+  ],+  "summary": "Updates a pet in the store with form data",+  "description": "",+  "operationId": "updatePetWithForm",+  "consumes": [+    "application/x-www-form-urlencoded"+  ],+  "produces": [+    "application/json",+    "application/xml"+  ],+  "parameters": [+    {+      "name": "petId",+      "in": "path",+      "description": "ID of pet that needs to be updated",+      "required": true,+      "type": "string"+    },+    {+      "name": "name",+      "in": "formData",+      "description": "Updated name of the pet",+      "required": false,+      "type": "string"+    },+    {+      "name": "status",+      "in": "formData",+      "description": "Updated status of the pet",+      "required": false,+      "type": "string"+    }+  ],+  "responses": {+    "200": {+      "description": "Pet updated."+    },+    "405": {+      "description": "Invalid input"+    }+  },+  "security": [+    {+      "petstore_auth": [+        "write:pets",+        "read:pets"+      ]+    }+  ]+}+|]++-- =======================================================================+-- Schema object+-- =======================================================================++schemaPrimitiveExample :: SwaggerSchema+schemaPrimitiveExample = mempty+  { _swaggerSchemaType = SwaggerSchemaString+  , _swaggerSchemaFormat = Just "email"+  }++schemaPrimitiveExampleJSON :: Value+schemaPrimitiveExampleJSON = [aesonQQ|+{+    "type": "string",+    "format": "email"+}+|]++schemaSimpleModelExample :: SwaggerSchema+schemaSimpleModelExample = mempty+  { _swaggerSchemaType = SwaggerSchemaObject+  , _swaggerSchemaRequired = [ "name" ]+  , _swaggerSchemaProperties =+      [ ("name", SwaggerInline mempty+            { _swaggerSchemaType = SwaggerSchemaString } )+      , ("address", SwaggerRef (SwaggerReference "#/definitions/Address"))+      , ("age", SwaggerInline mempty+            { _swaggerSchemaType = SwaggerSchemaInteger+            , _swaggerSchemaFormat = Just "int32"+            , _swaggerSchemaCommon = mempty+                { _swaggerSchemaMinimum = Just 0 } } ) ] }++schemaSimpleModelExampleJSON :: Value+schemaSimpleModelExampleJSON = [aesonQQ|+{+  "type": "object",+  "required": [+    "name"+  ],+  "properties": {+    "name": {+      "type": "string"+    },+    "address": {+      "$ref": "#/definitions/Address"+    },+    "age": {+      "type": "integer",+      "format": "int32",+      "minimum": 0+    }+  }+}+|]++schemaModelDictExample :: SwaggerSchema+schemaModelDictExample = mempty+  { _swaggerSchemaType = SwaggerSchemaObject+  , _swaggerSchemaAdditionalProperties = Just mempty+      { _swaggerSchemaType = SwaggerSchemaString } }++schemaModelDictExampleJSON :: Value+schemaModelDictExampleJSON = [aesonQQ|+{+  "type": "object",+  "additionalProperties": {+    "type": "string"+  }+}+|]++schemaWithExampleExample :: SwaggerSchema+schemaWithExampleExample = mempty+  { _swaggerSchemaType = SwaggerSchemaObject+  , _swaggerSchemaProperties =+      [ ("id", SwaggerInline mempty+            { _swaggerSchemaType   = SwaggerSchemaInteger+            , _swaggerSchemaFormat = Just "int64" })+      , ("name", SwaggerInline mempty+            { _swaggerSchemaType = SwaggerSchemaString }) ]+  , _swaggerSchemaRequired = [ "name" ]+  , _swaggerSchemaExample = Just [aesonQQ|+      {+        "name": "Puma",+        "id": 1+      }+    |] }++schemaWithExampleExampleJSON :: Value+schemaWithExampleExampleJSON = [aesonQQ|+{+  "type": "object",+  "properties": {+    "id": {+      "type": "integer",+      "format": "int64"+    },+    "name": {+      "type": "string"+    }+  },+  "required": [+    "name"+  ],+  "example": {+    "name": "Puma",+    "id": 1+  }+}+|]++-- =======================================================================+-- Definitions object+-- =======================================================================++definitionsExample :: HashMap Text SwaggerSchema+definitionsExample =+  [ ("Category", mempty+      { _swaggerSchemaType = SwaggerSchemaObject+      , _swaggerSchemaProperties =+          [ ("id", SwaggerInline mempty+              { _swaggerSchemaType = SwaggerSchemaInteger+              , _swaggerSchemaFormat = Just "int64" })+          , ("name", SwaggerInline mempty+              { _swaggerSchemaType = SwaggerSchemaString }) ] })+  , ("Tag", mempty+      { _swaggerSchemaType = SwaggerSchemaObject+      , _swaggerSchemaProperties =+          [ ("id", SwaggerInline mempty+              { _swaggerSchemaType = SwaggerSchemaInteger+              , _swaggerSchemaFormat = Just "int64" })+          , ("name", SwaggerInline mempty+              { _swaggerSchemaType = SwaggerSchemaString }) ] }) ]++definitionsExampleJSON :: Value+definitionsExampleJSON = [aesonQQ|+{+  "Category": {+    "type": "object",+    "properties": {+      "id": {+        "type": "integer",+        "format": "int64"+      },+      "name": {+        "type": "string"+      }+    }+  },+  "Tag": {+    "type": "object",+    "properties": {+      "id": {+        "type": "integer",+        "format": "int64"+      },+      "name": {+        "type": "string"+      }+    }+  }+}+|]++-- =======================================================================+-- Parameters Definition object+-- =======================================================================++parametersDefinitionExample :: HashMap Text SwaggerParameter+parametersDefinitionExample =+  [ ("skipParam", mempty+      { _swaggerParameterName = "skip"+      , _swaggerParameterDescription = Just "number of items to skip"+      , _swaggerParameterRequired = True+      , _swaggerParameterSchema = SwaggerParameterOther mempty+          { _swaggerParameterOtherSchemaIn = SwaggerParameterQuery+          , _swaggerParameterOtherSchemaType = SwaggerParamInteger+          , _swaggerParameterOtherSchemaFormat = Just "int32" } })+  , ("limitParam", mempty+      { _swaggerParameterName = "limit"+      , _swaggerParameterDescription = Just "max records to return"+      , _swaggerParameterRequired = True+      , _swaggerParameterSchema = SwaggerParameterOther mempty+          { _swaggerParameterOtherSchemaIn = SwaggerParameterQuery+          , _swaggerParameterOtherSchemaType = SwaggerParamInteger+          , _swaggerParameterOtherSchemaFormat = Just "int32" } }) ]++parametersDefinitionExampleJSON :: Value+parametersDefinitionExampleJSON = [aesonQQ|+{+  "skipParam": {+    "name": "skip",+    "in": "query",+    "description": "number of items to skip",+    "required": true,+    "type": "integer",+    "format": "int32"+  },+  "limitParam": {+    "name": "limit",+    "in": "query",+    "description": "max records to return",+    "required": true,+    "type": "integer",+    "format": "int32"+  }+}+|]++-- =======================================================================+-- Responses Definition object+-- =======================================================================++responsesDefinitionExample :: HashMap Text SwaggerResponse+responsesDefinitionExample =+  [ ("NotFound", mempty { _swaggerResponseDescription = "Entity not found." })+  , ("IllegalInput", mempty { _swaggerResponseDescription = "Illegal input for operation." }) ]++responsesDefinitionExampleJSON :: Value+responsesDefinitionExampleJSON = [aesonQQ|+{+  "NotFound": {+    "description": "Entity not found."+  },+  "IllegalInput": {+    "description": "Illegal input for operation."+  }+}+|]++-- =======================================================================+-- Responses Definition object+-- =======================================================================++securityDefinitionsExample :: HashMap Text SwaggerSecurityScheme+securityDefinitionsExample =+  [ ("api_key", SwaggerSecurityScheme+      { _swaggerSecuritySchemeType = SwaggerSecuritySchemeApiKey (SwaggerApiKeyParams "api_key" SwaggerApiKeyHeader)+      , _swaggerSecuritySchemeDescription = Nothing })+  , ("petstore_auth", SwaggerSecurityScheme+      { _swaggerSecuritySchemeType = SwaggerSecuritySchemeOAuth2 (SwaggerOAuth2Params+          { _swaggerOAuth2Flow = SwaggerOAuth2Implicit "http://swagger.io/api/oauth/dialog"+          , _swaggerOAuth2Scopes =+              [ ("write:pets",  "modify pets in your account")+              , ("read:pets", "read your pets") ] } )+      , _swaggerSecuritySchemeDescription = Nothing }) ]++securityDefinitionsExampleJSON :: Value+securityDefinitionsExampleJSON = [aesonQQ|+{+  "api_key": {+    "type": "apiKey",+    "name": "api_key",+    "in": "header"+  },+  "petstore_auth": {+    "type": "oauth2",+    "authorizationUrl": "http://swagger.io/api/oauth/dialog",+    "flow": "implicit",+    "scopes": {+      "write:pets": "modify pets in your account",+      "read:pets": "read your pets"+    }+  }+}+|]++-- =======================================================================+-- Swagger object+-- =======================================================================++swaggerExample :: Swagger+swaggerExample = mempty+  { _swaggerBasePath = Just "/"+  , _swaggerSchemes = Just [Http]+  , _swaggerInfo = mempty+      { _swaggerInfoVersion = "1.0"+      , _swaggerInfoTitle = "Todo API"+      , _swaggerInfoLicense = Just SwaggerLicense+          { _swaggerLicenseName = "MIT"+          , _swaggerLicenseUrl = Just (URL "http://mit.com") }+      , _swaggerInfoDescription = Just "This is a an API that tests servant-swagger support for a Todo API" }+  , _swaggerPaths = mempty+      { _swaggerPathsMap =+          [ ("/todo/{id}", mempty+              { _swaggerPathItemGet = Just mempty+                  { _swaggerOperationResponses = mempty+                      { _swaggerResponsesResponses =+                          [ (200, SwaggerInline mempty+                              { _swaggerResponseSchema = Just $ SwaggerInline mempty+                                { _swaggerSchemaExample = Just [aesonQQ|+                                    {+                                      "created": 100,+                                      "description": "get milk"+                                    } |]+                                , _swaggerSchemaType = SwaggerSchemaObject+                                , _swaggerSchemaDescription = Just "This is some real Todo right here"+                                , _swaggerSchemaProperties =+                                    [ ("created", SwaggerInline mempty+                                        { _swaggerSchemaType = SwaggerSchemaInteger+                                        , _swaggerSchemaFormat = Just "int32" })+                                    , ("description", SwaggerInline mempty+                                        { _swaggerSchemaType = SwaggerSchemaString }) ] }+                              , _swaggerResponseDescription = "OK" }) ] }+                  , _swaggerOperationProduces = Just (SwaggerMimeList [ "application/json" ])+                  , _swaggerOperationParameters =+                      [ SwaggerInline mempty+                          { _swaggerParameterRequired = True+                          , _swaggerParameterName = "id"+                          , _swaggerParameterDescription = Just "TodoId param"+                          , _swaggerParameterSchema = SwaggerParameterOther mempty+                              { _swaggerParameterOtherSchemaIn = SwaggerParameterPath+                              , _swaggerParameterOtherSchemaType = SwaggerParamString } } ]+                  , _swaggerOperationTags = [ "todo" ] } }) ] } }++swaggerExampleJSON :: Value+swaggerExampleJSON = [aesonQQ|+{+    "swagger": "2.0",+    "basePath": "/",+    "schemes": [+        "http"+    ],+    "info": {+        "version": "1.0",+        "title": "Todo API",+        "license": {+            "url": "http://mit.com",+            "name": "MIT"+        },+        "description": "This is a an API that tests servant-swagger support for a Todo API"+    },+    "paths": {+        "/todo/{id}": {+            "get": {+                "responses": {+                    "200": {+                        "schema": {+                            "example": {+                                "created": 100,+                                "description": "get milk"+                            },+                            "type": "object",+                            "description": "This is some real Todo right here",+                            "properties": {+                                "created": {+                                    "format": "int32",+                                    "type": "integer"+                                },+                                "description": {+                                    "type": "string"+                                }+                            }+                        },+                        "description": "OK"+                    }+                },+                "produces": [+                    "application/json"+                ],+                "parameters": [+                    {+                        "required": true,+                        "in": "path",+                        "name": "id",+                        "type": "string",+                        "description": "TodoId param"+                    }+                ],+                "tags": [+                    "todo"+                ]+            }+        }+    }+}+|]++petstoreExampleJSON :: Value+petstoreExampleJSON = [aesonQQ|+{  +   "swagger":"2.0",+   "info":{  +      "description":"This is a sample server Petstore server.  You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).  For this sample, you can use the api key `special-key` to test the authorization filters.",+      "version":"1.0.0",+      "title":"Swagger Petstore",+      "termsOfService":"http://swagger.io/terms/",+      "contact":{  +         "email":"apiteam@swagger.io"+      },+      "license":{  +         "name":"Apache 2.0",+         "url":"http://www.apache.org/licenses/LICENSE-2.0.html"+      }+   },+   "host":"petstore.swagger.io",+   "basePath":"/v2",+   "tags":[  +      {  +         "name":"pet",+         "description":"Everything about your Pets",+         "externalDocs":{  +            "description":"Find out more",+            "url":"http://swagger.io"+         }+      },+      {  +         "name":"store",+         "description":"Access to Petstore orders"+      },+      {  +         "name":"user",+         "description":"Operations about user",+         "externalDocs":{  +            "description":"Find out more about our store",+            "url":"http://swagger.io"+         }+      }+   ],+   "schemes":[  +      "http"+   ],+   "paths":{  +      "/pet":{  +         "post":{  +            "tags":[  +               "pet"+            ],+            "summary":"Add a new pet to the store",+            "description":"",+            "operationId":"addPet",+            "consumes":[  +               "application/json",+               "application/xml"+            ],+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "in":"body",+                  "name":"body",+                  "description":"Pet object that needs to be added to the store",+                  "required":true,+                  "schema":{  +                     "$ref":"#/definitions/Pet"+                  }+               }+            ],+            "responses":{  +               "405":{  +                  "description":"Invalid input"+               }+            },+            "security":[  +               {  +                  "petstore_auth":[  +                     "write:pets",+                     "read:pets"+                  ]+               }+            ]+         },+         "put":{  +            "tags":[  +               "pet"+            ],+            "summary":"Update an existing pet",+            "description":"",+            "operationId":"updatePet",+            "consumes":[  +               "application/json",+               "application/xml"+            ],+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "in":"body",+                  "name":"body",+                  "description":"Pet object that needs to be added to the store",+                  "required":true,+                  "schema":{  +                     "$ref":"#/definitions/Pet"+                  }+               }+            ],+            "responses":{  +               "400":{  +                  "description":"Invalid ID supplied"+               },+               "404":{  +                  "description":"Pet not found"+               },+               "405":{  +                  "description":"Validation exception"+               }+            },+            "security":[  +               {  +                  "petstore_auth":[  +                     "write:pets",+                     "read:pets"+                  ]+               }+            ]+         }+      },+      "/pet/findByStatus":{  +         "get":{  +            "tags":[  +               "pet"+            ],+            "summary":"Finds Pets by status",+            "description":"Multiple status values can be provided with comma seperated strings",+            "operationId":"findPetsByStatus",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"status",+                  "in":"query",+                  "description":"Status values that need to be considered for filter",+                  "required":true,+                  "type":"array",+                  "items":{  +                     "type":"string",+                     "enum":[  +                        "available",+                        "pending",+                        "sold"+                     ],+                     "default":"available"+                  },+                  "collectionFormat":"csv"+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "type":"array",+                     "items":{  +                        "$ref":"#/definitions/Pet"+                     }+                  }+               },+               "400":{  +                  "description":"Invalid status value"+               }+            },+            "security":[  +               {  +                  "petstore_auth":[  +                     "write:pets",+                     "read:pets"+                  ]+               }+            ]+         }+      },+      "/pet/findByTags":{  +         "get":{  +            "tags":[  +               "pet"+            ],+            "summary":"Finds Pets by tags",+            "description":"Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.",+            "operationId":"findPetsByTags",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"tags",+                  "in":"query",+                  "description":"Tags to filter by",+                  "required":true,+                  "type":"array",+                  "items":{  +                     "type":"string"+                  },+                  "collectionFormat":"csv"+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "type":"array",+                     "items":{  +                        "$ref":"#/definitions/Pet"+                     }+                  }+               },+               "400":{  +                  "description":"Invalid tag value"+               }+            },+            "security":[  +               {  +                  "petstore_auth":[  +                     "write:pets",+                     "read:pets"+                  ]+               }+            ]+         }+      },+      "/pet/{petId}":{  +         "get":{  +            "tags":[  +               "pet"+            ],+            "summary":"Find pet by ID",+            "description":"Returns a single pet",+            "operationId":"getPetById",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"petId",+                  "in":"path",+                  "description":"ID of pet to return",+                  "required":true,+                  "type":"integer",+                  "format":"int64"+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "$ref":"#/definitions/Pet"+                  }+               },+               "400":{  +                  "description":"Invalid ID supplied"+               },+               "404":{  +                  "description":"Pet not found"+               }+            },+            "security":[  +               {  +                  "api_key":[  +                  ]+               }+            ]+         },+         "post":{  +            "tags":[  +               "pet"+            ],+            "summary":"Updates a pet in the store with form data",+            "description":"",+            "operationId":"updatePetWithForm",+            "consumes":[  +               "application/x-www-form-urlencoded"+            ],+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"petId",+                  "in":"path",+                  "description":"ID of pet that needs to be updated",+                  "required":true,+                  "type":"integer",+                  "format":"int64"+               },+               {  +                  "name":"name",+                  "in":"formData",+                  "description":"Updated name of the pet",+                  "required":false,+                  "type":"string"+               },+               {  +                  "name":"status",+                  "in":"formData",+                  "description":"Updated status of the pet",+                  "required":false,+                  "type":"string"+               }+            ],+            "responses":{  +               "405":{  +                  "description":"Invalid input"+               }+            },+            "security":[  +               {  +                  "petstore_auth":[  +                     "write:pets",+                     "read:pets"+                  ]+               }+            ]+         },+         "delete":{  +            "tags":[  +               "pet"+            ],+            "summary":"Deletes a pet",+            "description":"",+            "operationId":"deletePet",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"api_key",+                  "in":"header",+                  "required":false,+                  "type":"string"+               },+               {  +                  "name":"petId",+                  "in":"path",+                  "description":"Pet id to delete",+                  "required":true,+                  "type":"integer",+                  "format":"int64"+               }+            ],+            "responses":{  +               "400":{  +                  "description":"Invalid pet value"+               }+            },+            "security":[  +               {  +                  "petstore_auth":[  +                     "write:pets",+                     "read:pets"+                  ]+               }+            ]+         }+      },+      "/pet/{petId}/uploadImage":{  +         "post":{  +            "tags":[  +               "pet"+            ],+            "summary":"uploads an image",+            "description":"",+            "operationId":"uploadFile",+            "consumes":[  +               "multipart/form-data"+            ],+            "produces":[  +               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"petId",+                  "in":"path",+                  "description":"ID of pet to update",+                  "required":true,+                  "type":"integer",+                  "format":"int64"+               },+               {  +                  "name":"additionalMetadata",+                  "in":"formData",+                  "description":"Additional data to pass to server",+                  "required":false,+                  "type":"string"+               },+               {  +                  "name":"file",+                  "in":"formData",+                  "description":"file to upload",+                  "required":false,+                  "type":"file"+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "$ref":"#/definitions/ApiResponse"+                  }+               }+            },+            "security":[  +               {  +                  "petstore_auth":[  +                     "write:pets",+                     "read:pets"+                  ]+               }+            ]+         }+      },+      "/store/inventory":{  +         "get":{  +            "tags":[  +               "store"+            ],+            "summary":"Returns pet inventories by status",+            "description":"Returns a map of status codes to quantities",+            "operationId":"getInventory",+            "produces":[  +               "application/json"+            ],+            "parameters":[  +            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "type":"object",+                     "additionalProperties":{  +                        "type":"integer",+                        "format":"int32"+                     }+                  }+               }+            },+            "security":[  +               {  +                  "api_key":[  +                  ]+               }+            ]+         }+      },+      "/store/order":{  +         "post":{  +            "tags":[  +               "store"+            ],+            "summary":"Place an order for a pet",+            "description":"",+            "operationId":"placeOrder",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "in":"body",+                  "name":"body",+                  "description":"order placed for purchasing the pet",+                  "required":true,+                  "schema":{  +                     "$ref":"#/definitions/Order"+                  }+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "$ref":"#/definitions/Order"+                  }+               },+               "400":{  +                  "description":"Invalid Order"+               }+            }+         }+      },+      "/store/order/{orderId}":{  +         "get":{  +            "tags":[  +               "store"+            ],+            "summary":"Find purchase order by ID",+            "description":"For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions",+            "operationId":"getOrderById",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"orderId",+                  "in":"path",+                  "description":"ID of pet that needs to be fetched",+                  "required":true,+                  "type":"integer",+                  "maximum":5.0,+                  "minimum":1.0,+                  "format":"int64"+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "$ref":"#/definitions/Order"+                  }+               },+               "400":{  +                  "description":"Invalid ID supplied"+               },+               "404":{  +                  "description":"Order not found"+               }+            }+         },+         "delete":{  +            "tags":[  +               "store"+            ],+            "summary":"Delete purchase order by ID",+            "description":"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors",+            "operationId":"deleteOrder",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"orderId",+                  "in":"path",+                  "description":"ID of the order that needs to be deleted",+                  "required":true,+                  "type":"string",+                  "minimum":1.0+               }+            ],+            "responses":{  +               "400":{  +                  "description":"Invalid ID supplied"+               },+               "404":{  +                  "description":"Order not found"+               }+            }+         }+      },+      "/user":{  +         "post":{  +            "tags":[  +               "user"+            ],+            "summary":"Create user",+            "description":"This can only be done by the logged in user.",+            "operationId":"createUser",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "in":"body",+                  "name":"body",+                  "description":"Created user object",+                  "required":true,+                  "schema":{  +                     "$ref":"#/definitions/User"+                  }+               }+            ],+            "responses":{  +               "default":{  +                  "description":"successful operation"+               }+            }+         }+      },+      "/user/createWithArray":{  +         "post":{  +            "tags":[  +               "user"+            ],+            "summary":"Creates list of users with given input array",+            "description":"",+            "operationId":"createUsersWithArrayInput",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "in":"body",+                  "name":"body",+                  "description":"List of user object",+                  "required":true,+                  "schema":{  +                     "type":"array",+                     "items":{  +                        "$ref":"#/definitions/User"+                     }+                  }+               }+            ],+            "responses":{  +               "default":{  +                  "description":"successful operation"+               }+            }+         }+      },+      "/user/createWithList":{  +         "post":{  +            "tags":[  +               "user"+            ],+            "summary":"Creates list of users with given input array",+            "description":"",+            "operationId":"createUsersWithListInput",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "in":"body",+                  "name":"body",+                  "description":"List of user object",+                  "required":true,+                  "schema":{  +                     "type":"array",+                     "items":{  +                        "$ref":"#/definitions/User"+                     }+                  }+               }+            ],+            "responses":{  +               "default":{  +                  "description":"successful operation"+               }+            }+         }+      },+      "/user/login":{  +         "get":{  +            "tags":[  +               "user"+            ],+            "summary":"Logs user into the system",+            "description":"",+            "operationId":"loginUser",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"username",+                  "in":"query",+                  "description":"The user name for login",+                  "required":true,+                  "type":"string"+               },+               {  +                  "name":"password",+                  "in":"query",+                  "description":"The password for login in clear text",+                  "required":true,+                  "type":"string"+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "type":"string"+                  },+                  "headers":{  +                     "X-Rate-Limit":{  +                        "type":"integer",+                        "format":"int32",+                        "description":"calls per hour allowed by the user"+                     },+                     "X-Expires-After":{  +                        "type":"string",+                        "format":"date-time",+                        "description":"date in UTC when toekn expires"+                     }+                  }+               },+               "400":{  +                  "description":"Invalid username/password supplied"+               }+            }+         }+      },+      "/user/logout":{  +         "get":{  +            "tags":[  +               "user"+            ],+            "summary":"Logs out current logged in user session",+            "description":"",+            "operationId":"logoutUser",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +            ],+            "responses":{  +               "default":{  +                  "description":"successful operation"+               }+            }+         }+      },+      "/user/{username}":{  +         "get":{  +            "tags":[  +               "user"+            ],+            "summary":"Get user by user name",+            "description":"",+            "operationId":"getUserByName",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"username",+                  "in":"path",+                  "description":"The name that needs to be fetched. Use user1 for testing. ",+                  "required":true,+                  "type":"string"+               }+            ],+            "responses":{  +               "200":{  +                  "description":"successful operation",+                  "schema":{  +                     "$ref":"#/definitions/User"+                  }+               },+               "400":{  +                  "description":"Invalid username supplied"+               },+               "404":{  +                  "description":"User not found"+               }+            }+         },+         "put":{  +            "tags":[  +               "user"+            ],+            "summary":"Updated user",+            "description":"This can only be done by the logged in user.",+            "operationId":"updateUser",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"username",+                  "in":"path",+                  "description":"name that need to be deleted",+                  "required":true,+                  "type":"string"+               },+               {  +                  "in":"body",+                  "name":"body",+                  "description":"Updated user object",+                  "required":true,+                  "schema":{  +                     "$ref":"#/definitions/User"+                  }+               }+            ],+            "responses":{  +               "400":{  +                  "description":"Invalid user supplied"+               },+               "404":{  +                  "description":"User not found"+               }+            }+         },+         "delete":{  +            "tags":[  +               "user"+            ],+            "summary":"Delete user",+            "description":"This can only be done by the logged in user.",+            "operationId":"deleteUser",+            "produces":[  +               "application/xml",+               "application/json"+            ],+            "parameters":[  +               {  +                  "name":"username",+                  "in":"path",+                  "description":"The name that needs to be deleted",+                  "required":true,+                  "type":"string"+               }+            ],+            "responses":{  +               "400":{  +                  "description":"Invalid username supplied"+               },+               "404":{  +                  "description":"User not found"+               }+            }+         }+      }+   },+   "securityDefinitions":{  +      "petstore_auth":{  +         "type":"oauth2",+         "authorizationUrl":"http://petstore.swagger.io/api/oauth/dialog",+         "flow":"implicit",+         "scopes":{  +            "write:pets":"modify pets in your account",+            "read:pets":"read your pets"+         }+      },+      "api_key":{  +         "type":"apiKey",+         "name":"api_key",+         "in":"header"+      }+   },+   "definitions":{  +      "Order":{  +         "type":"object",+         "properties":{  +            "id":{  +               "type":"integer",+               "format":"int64"+            },+            "petId":{  +               "type":"integer",+               "format":"int64"+            },+            "quantity":{  +               "type":"integer",+               "format":"int32"+            },+            "shipDate":{  +               "type":"string",+               "format":"date-time"+            },+            "status":{  +               "type":"string",+               "description":"Order Status",+               "enum":[  +                  "placed",+                  "approved",+                  "delivered"+               ]+            },+            "complete":{  +               "type":"boolean",+               "default":false+            }+         },+         "xml":{  +            "name":"Order"+         }+      },+      "Category":{  +         "type":"object",+         "properties":{  +            "id":{  +               "type":"integer",+               "format":"int64"+            },+            "name":{  +               "type":"string"+            }+         },+         "xml":{  +            "name":"Category"+         }+      },+      "User":{  +         "type":"object",+         "properties":{  +            "id":{  +               "type":"integer",+               "format":"int64"+            },+            "username":{  +               "type":"string"+            },+            "firstName":{  +               "type":"string"+            },+            "lastName":{  +               "type":"string"+            },+            "email":{  +               "type":"string"+            },+            "password":{  +               "type":"string"+            },+            "phone":{  +               "type":"string"+            },+            "userStatus":{  +               "type":"integer",+               "format":"int32",+               "description":"User Status"+            }+         },+         "xml":{  +            "name":"User"+         }+      },+      "Tag":{  +         "type":"object",+         "properties":{  +            "id":{  +               "type":"integer",+               "format":"int64"+            },+            "name":{  +               "type":"string"+            }+         },+         "xml":{  +            "name":"Tag"+         }+      },+      "Pet":{  +         "type":"object",+         "required":[  +            "name",+            "photoUrls"+         ],+         "properties":{  +            "id":{  +               "type":"integer",+               "format":"int64"+            },+            "category":{  +               "$ref":"#/definitions/Category"+            },+            "name":{  +               "type":"string",+               "example":"doggie"+            },+            "photoUrls":{  +               "type":"array",+               "xml":{  +                  "name":"photoUrl",+                  "wrapped":true+               },+               "items":{  +                  "type":"string"+               }+            },+            "tags":{  +               "type":"array",+               "xml":{  +                  "name":"tag",+                  "wrapped":true+               },+               "items":{  +                  "$ref":"#/definitions/Tag"+               }+            },+            "status":{  +               "type":"string",+               "description":"pet status in the store",+               "enum":[  +                  "available",+                  "pending",+                  "sold"+               ]+            }+         },+         "xml":{  +            "name":"Pet"+         }+      },+      "ApiResponse":{  +         "type":"object",+         "properties":{  +            "code":{  +               "type":"integer",+               "format":"int32"+            },+            "type":{  +               "type":"string"+            },+            "message":{  +               "type":"string"+            }+         }+      }+   },+   "externalDocs":{  +      "description":"Find out more about Swagger",+      "url":"http://swagger.io"+   } } |]