@@ -3,20 +3,28 @@
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE RecordWildCards #-}
5{-# LANGUAGE RecordWildCards #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE TemplateHaskell #-}
7{-# LANGUAGE TemplateHaskell #-}
7module Data.Swagger.Internal where
8module Data.Swagger.Internal where
10+import Control.Applicative
9import Data.Aeson
12import Data.Aeson
10−import Data.Aeson.TH (deriveToJSON)
13+import Data.Aeson.TH (deriveJSON)
11import Data.Foldable (Foldable)
14import Data.Foldable (Foldable)
12import Data.HashMap.Strict (HashMap)
15import Data.HashMap.Strict (HashMap)
13import qualified Data.HashMap.Strict as HashMap
16import qualified Data.HashMap.Strict as HashMap
18+import qualified Data.Map as Map
19+import Data.String (fromString)
14import Data.Text (Text)
20import Data.Text (Text)
21+import qualified Data.Text as Text
15import Data.Traversable (Traversable)
22import Data.Traversable (Traversable)
16import Data.Hashable (Hashable)
23import Data.Hashable (Hashable)
17import GHC.Generics (Generic)
24import GHC.Generics (Generic)
18import Network (HostName, PortNumber)
25import Network (HostName, PortNumber)
19import Network.HTTP.Media (MediaType)
26import Network.HTTP.Media (MediaType)
27+import Text.Read (readMaybe)
21import Data.Swagger.Internal.Utils
29import Data.Swagger.Internal.Utils
@@ -133,12 +141,6 @@ data SwaggerHost = SwaggerHost
133 , swaggerHostPort :: Maybe PortNumber -- ^ Optional port.
141 , swaggerHostPort :: Maybe PortNumber -- ^ Optional port.
134 } deriving (Show)
142 } deriving (Show)
136−instance ToJSON SwaggerHost where
137− toJSON (SwaggerHost host mport) = toJSON $
140− Just port -> host ++ ":" ++ show port
142-- | The transfer protocol of the API.
144-- | The transfer protocol of the API.
143data SwaggerScheme
145data SwaggerScheme
@@ -154,9 +156,6 @@ data SwaggerPaths = SwaggerPaths
154 swaggerPathsMap :: HashMap FilePath SwaggerPathItem
156 swaggerPathsMap :: HashMap FilePath SwaggerPathItem
155 } deriving (Show)
157 } deriving (Show)
157−instance ToJSON SwaggerPaths where
158− toJSON (SwaggerPaths m) = toJSON m
160-- | Describes the operations available on a single path.
159-- | Describes the operations available on a single path.
161-- A @'SwaggerPathItem'@ may be empty, due to ACL constraints.
160-- A @'SwaggerPathItem'@ may be empty, due to ACL constraints.
162-- The path itself is still exposed to the documentation viewer
161-- The path itself is still exposed to the documentation viewer
@@ -253,9 +252,6 @@ data SwaggerOperation = SwaggerOperation
253newtype SwaggerMimeList = SwaggerMimeList { getSwaggerMimeList :: [MediaType] }
252newtype SwaggerMimeList = SwaggerMimeList { getSwaggerMimeList :: [MediaType] }
254 deriving (Show)
253 deriving (Show)
256−instance ToJSON SwaggerMimeList where
257− toJSON (SwaggerMimeList xs) = toJSON (map show xs)
259-- | Describes a single operation parameter.
255-- | Describes a single operation parameter.
260-- A unique parameter is defined by a combination of a name and location.
256-- A unique parameter is defined by a combination of a name and location.
261data SwaggerParameter = SwaggerParameter
257data SwaggerParameter = SwaggerParameter
@@ -277,18 +273,11 @@ data SwaggerParameter = SwaggerParameter
277 , swaggerParameterSchema :: SwaggerParameterSchema
273 , swaggerParameterSchema :: SwaggerParameterSchema
278 } deriving (Show, Generic)
274 } deriving (Show, Generic)
280−instance ToJSON SwaggerParameter where
281− toJSON = genericToJSONWithSub "schema" (jsonPrefix "swaggerParameter")
283data SwaggerParameterSchema
276data SwaggerParameterSchema
284 = SwaggerParameterBody SwaggerSchema
277 = SwaggerParameterBody SwaggerSchema
285 | SwaggerParameterOther SwaggerParameterOtherSchema
278 | SwaggerParameterOther SwaggerParameterOtherSchema
286 deriving (Show)
279 deriving (Show)
288−instance ToJSON SwaggerParameterSchema where
289− toJSON (SwaggerParameterBody s) = toJSON s <+> object [ "in" .= ("body" :: Text) ]
290− toJSON (SwaggerParameterOther s) = toJSON s
292data SwaggerParameterOtherSchema = SwaggerParameterOtherSchema
281data SwaggerParameterOtherSchema = SwaggerParameterOtherSchema
293 { -- | The location of the parameter.
282 { -- | The location of the parameter.
294 swaggerParameterOtherSchemaIn :: SwaggerParameterLocation
283 swaggerParameterOtherSchemaIn :: SwaggerParameterLocation
@@ -321,9 +310,6 @@ data SwaggerParameterOtherSchema = SwaggerParameterOtherSchema
321 , swaggerParameterOtherSchemaCommon :: SwaggerSchemaCommon
310 , swaggerParameterOtherSchemaCommon :: SwaggerSchemaCommon
322 } deriving (Show, Generic)
311 } deriving (Show, Generic)
324−instance ToJSON SwaggerParameterOtherSchema where
325− toJSON = genericToJSONWithSub "common" (jsonPrefix "swaggerParameterOtherSchema")
327data SwaggerParameterType
313data SwaggerParameterType
328 = SwaggerParamString
314 = SwaggerParamString
329 | SwaggerParamNumber
315 | SwaggerParamNumber
@@ -421,10 +407,6 @@ data SwaggerSchemaItems
421 | SwaggerSchemaItemsArray [SwaggerSchema]
407 | SwaggerSchemaItemsArray [SwaggerSchema]
422 deriving (Show)
408 deriving (Show)
424−instance ToJSON SwaggerSchemaItems where
425− toJSON (SwaggerSchemaItemsObject x) = toJSON x
426− toJSON (SwaggerSchemaItemsArray xs) = toJSON xs
428data SwaggerSchemaCommon = SwaggerSchemaCommon
410data SwaggerSchemaCommon = SwaggerSchemaCommon
429 { -- | Declares the value of the parameter that the server will use if none is provided,
411 { -- | Declares the value of the parameter that the server will use if none is provided,
430 -- for example a @"count"@ to control the number of results per page might default to @100@
412 -- for example a @"count"@ to control the number of results per page might default to @100@
@@ -508,11 +490,6 @@ data SwaggerResponses = SwaggerResponses
508 , swaggerResponsesResponses :: HashMap HttpStatusCode SwaggerResponse
490 , swaggerResponsesResponses :: HashMap HttpStatusCode SwaggerResponse
509 } deriving (Show)
491 } deriving (Show)
511−instance ToJSON SwaggerResponses where
512− toJSON (SwaggerResponses def rs) = object
514− , "responses" .= hashMapMapKeys show rs ]
516type HttpStatusCode = Int
493type HttpStatusCode = Int
518-- | Describes a single response from an API Operation.
495-- | Describes a single response from an API Operation.
@@ -558,12 +535,9 @@ data SwaggerHeader = SwaggerHeader
558 , swaggerHeaderCommon :: SwaggerSchemaCommon
535 , swaggerHeaderCommon :: SwaggerSchemaCommon
559 } deriving (Show, Generic)
536 } deriving (Show, Generic)
561−data SwaggerExample = SwaggerExample { getSwaggerExample :: HashMap MediaType Value }
538+data SwaggerExample = SwaggerExample { getSwaggerExample :: Map MediaType Value }
562 deriving (Show)
539 deriving (Show)
564−instance ToJSON SwaggerExample where
565− toJSON = toJSON . hashMapMapKeys show . getSwaggerExample
567-- | The location of the API key.
541-- | The location of the API key.
568data SwaggerApiKeyLocation
542data SwaggerApiKeyLocation
569 = SwaggerApiKeyQuery
543 = SwaggerApiKeyQuery
@@ -611,10 +585,16 @@ data SwaggerSecuritySchemeTypeName
611 | SwaggerSecuritySchemeTypeOAuth2
585 | SwaggerSecuritySchemeTypeOAuth2
612 deriving (Eq, Read, Show, Generic)
586 deriving (Eq, Read, Show, Generic)
614−swaggerSecuritySchemeTypeNameText :: SwaggerSecuritySchemeTypeName -> Text
588+swaggerSecuritySchemeTypeNameToText :: SwaggerSecuritySchemeTypeName -> Text
615−swaggerSecuritySchemeTypeNameText SwaggerSecuritySchemeTypeBasic = "basic"
589+swaggerSecuritySchemeTypeNameToText SwaggerSecuritySchemeTypeBasic = "basic"
616−swaggerSecuritySchemeTypeNameText SwaggerSecuritySchemeTypeApiKey = "apiKey"
590+swaggerSecuritySchemeTypeNameToText SwaggerSecuritySchemeTypeApiKey = "apiKey"
617−swaggerSecuritySchemeTypeNameText SwaggerSecuritySchemeTypeOAuth2 = "oauth2"
591+swaggerSecuritySchemeTypeNameToText SwaggerSecuritySchemeTypeOAuth2 = "oauth2"
593+swaggerSecuritySchemeTypeNameFromText :: Alternative f => Text -> f SwaggerSecuritySchemeTypeName
594+swaggerSecuritySchemeTypeNameFromText "basic" = pure SwaggerSecuritySchemeTypeBasic
595+swaggerSecuritySchemeTypeNameFromText "apiKey" = pure SwaggerSecuritySchemeTypeApiKey
596+swaggerSecuritySchemeTypeNameFromText "oauth2" = pure SwaggerSecuritySchemeTypeOAuth2
597+swaggerSecuritySchemeTypeNameFromText _ = empty
619instance Hashable SwaggerSecuritySchemeTypeName
599instance Hashable SwaggerSecuritySchemeTypeName
@@ -633,9 +613,6 @@ newtype SwaggerSecurityRequirement = SwaggerSecurityRequirement
633 { getSwaggerSecurityRequirement :: HashMap SwaggerSecuritySchemeTypeName Text
613 { getSwaggerSecurityRequirement :: HashMap SwaggerSecuritySchemeTypeName Text
634 } deriving (Eq, Read, Show, Monoid)
614 } deriving (Eq, Read, Show, Monoid)
636−instance ToJSON SwaggerSecurityRequirement where
637− toJSON (SwaggerSecurityRequirement m) = toJSON (hashMapMapKeys swaggerSecuritySchemeTypeNameText m)
639-- | Allows adding meta data to a single tag that is used by @SwaggerOperation@.
616-- | Allows adding meta data to a single tag that is used by @SwaggerOperation@.
640-- It is not mandatory to have a @SwaggerTag@ per tag used there.
617-- It is not mandatory to have a @SwaggerTag@ per tag used there.
641data SwaggerTag = SwaggerTag
618data SwaggerTag = SwaggerTag
@@ -662,26 +639,34 @@ data SwaggerExternalDocs = SwaggerExternalDocs
663newtype URL = URL { getUrl :: Text } deriving (Show, ToJSON, FromJSON)
640newtype URL = URL { getUrl :: Text } deriving (Show, ToJSON, FromJSON)
642+-- =======================================================================
643+-- TH derived ToJSON and FromJSON instances
644+-- =======================================================================
665−deriveToJSON' ''SwaggerOperation
646+deriveJSON' ''SwaggerOperation
666−deriveToJSON (jsonPrefix "SwaggerParameter") ''SwaggerParameterLocation
647+deriveJSON (jsonPrefix "SwaggerParameter") ''SwaggerParameterLocation
667−deriveToJSON (jsonPrefix "SwaggerParam") ''SwaggerParameterType
648+deriveJSON (jsonPrefix "SwaggerParam") ''SwaggerParameterType
668−deriveToJSON' ''SwaggerPathItem
649+deriveJSON' ''SwaggerPathItem
669−deriveToJSON' ''SwaggerInfo
650+deriveJSON' ''SwaggerInfo
670−deriveToJSON' ''SwaggerContact
651+deriveJSON' ''SwaggerContact
671−deriveToJSON' ''SwaggerLicense
652+deriveJSON' ''SwaggerLicense
672−deriveToJSON (jsonPrefix "SwaggerSchema") ''SwaggerSchemaType
653+deriveJSON (jsonPrefix "SwaggerSchema") ''SwaggerSchemaType
673−deriveToJSON (jsonPrefix "SwaggerItems") ''SwaggerItemsType
654+deriveJSON (jsonPrefix "SwaggerItems") ''SwaggerItemsType
674−deriveToJSON (jsonPrefix "SwaggerItemsCollection") ''SwaggerItemsCollectionFormat
655+deriveJSON (jsonPrefix "SwaggerItemsCollection") ''SwaggerItemsCollectionFormat
675−deriveToJSON (jsonPrefix "SwaggerCollection") ''SwaggerCollectionFormat
656+deriveJSON (jsonPrefix "SwaggerCollection") ''SwaggerCollectionFormat
676−deriveToJSON (jsonPrefix "SwaggerSecuritySchemeType") ''SwaggerSecuritySchemeTypeName
657+deriveJSON (jsonPrefix "SwaggerSecuritySchemeType") ''SwaggerSecuritySchemeTypeName
677−deriveToJSON (jsonPrefix "SwaggerApiKey") ''SwaggerApiKeyLocation
658+deriveJSON (jsonPrefix "SwaggerApiKey") ''SwaggerApiKeyLocation
678−deriveToJSON (jsonPrefix "swaggerApiKey") ''SwaggerApiKeyParams
659+deriveJSON (jsonPrefix "swaggerApiKey") ''SwaggerApiKeyParams
679−deriveToJSON' ''SwaggerResponse
660+deriveJSON' ''SwaggerResponse
680−deriveToJSON' ''SwaggerSchemaCommon
661+deriveJSON' ''SwaggerSchemaCommon
681−deriveToJSONDefault ''SwaggerScheme
662+deriveJSONDefault ''SwaggerScheme
682−deriveToJSON' ''SwaggerTag
663+deriveJSON' ''SwaggerTag
683−deriveToJSON' ''SwaggerExternalDocs
664+deriveJSON' ''SwaggerExternalDocs
684−deriveToJSON' ''SwaggerXml
665+deriveJSON' ''SwaggerXml
667+-- =======================================================================
668+-- Manual ToJSON instances
669+-- =======================================================================
686instance ToJSON SwaggerOAuth2Flow where
671instance ToJSON SwaggerOAuth2Flow where
687 toJSON (SwaggerOAuth2Implicit authUrl) = object
672 toJSON (SwaggerOAuth2Implicit authUrl) = object
@@ -729,3 +714,139 @@ instance ToJSON SwaggerHeader where
729instance ToJSON SwaggerItems where
714instance ToJSON SwaggerItems where
730 toJSON = genericToJSONWithSub "common" (jsonPrefix "swaggerItems")
715 toJSON = genericToJSONWithSub "common" (jsonPrefix "swaggerItems")
717+instance ToJSON SwaggerHost where
718+ toJSON (SwaggerHost host mport) = toJSON $
721+ Just port -> host ++ ":" ++ show port
723+instance ToJSON SwaggerPaths where
724+ toJSON (SwaggerPaths m) = toJSON m
726+instance ToJSON SwaggerMimeList where
727+ toJSON (SwaggerMimeList xs) = toJSON (map show xs)
729+instance ToJSON SwaggerParameter where
730+ toJSON = genericToJSONWithSub "schema" (jsonPrefix "swaggerParameter")
732+instance ToJSON SwaggerParameterSchema where
733+ toJSON (SwaggerParameterBody s) = toJSON s <+> object [ "in" .= ("body" :: Text) ]
734+ toJSON (SwaggerParameterOther s) = toJSON s
736+instance ToJSON SwaggerParameterOtherSchema where
737+ toJSON = genericToJSONWithSub "common" (jsonPrefix "swaggerParameterOtherSchema")
739+instance ToJSON SwaggerSchemaItems where
740+ toJSON (SwaggerSchemaItemsObject x) = toJSON x
741+ toJSON (SwaggerSchemaItemsArray xs) = toJSON xs
743+instance ToJSON SwaggerResponses where
744+ toJSON (SwaggerResponses def rs) = object
746+ , "responses" .= hashMapMapKeys show rs ]
748+instance ToJSON SwaggerExample where
749+ toJSON = toJSON . Map.mapKeys show . getSwaggerExample
751+instance ToJSON SwaggerSecurityRequirement where
752+ toJSON (SwaggerSecurityRequirement m) = toJSON (hashMapMapKeys swaggerSecuritySchemeTypeNameToText m)
754+-- =======================================================================
755+-- Manual FromJSON instances
756+-- =======================================================================
758+instance FromJSON SwaggerOAuth2Flow where
759+ parseJSON (Object o) = do
760+ (flow :: Text) <- o .: "flow"
762+ "implicit" -> SwaggerOAuth2Implicit <$> o .: "authorizationUrl"
763+ "password" -> SwaggerOAuth2Password <$> o .: "tokenUrl"
764+ "application" -> SwaggerOAuth2Application <$> o .: "tokenUrl"
765+ "accessCode" -> SwaggerOAuth2AccessCode
766+ <$> o .: "authorizationUrl"
771+instance FromJSON SwaggerOAuth2Params where
772+ parseJSON = genericParseJSONWithSub "flow" (jsonPrefix "swaggerOAuth2")
774+instance FromJSON SwaggerSecuritySchemeType where
775+ parseJSON json@(Object o) = do
778+ SwaggerSecuritySchemeTypeBasic -> pure SwaggerSecuritySchemeBasic
779+ SwaggerSecuritySchemeTypeApiKey -> SwaggerSecuritySchemeApiKey <$> parseJSON json
780+ SwaggerSecuritySchemeTypeOAuth2 -> SwaggerSecuritySchemeOAuth2 <$> parseJSON json
783+instance FromJSON Swagger where
784+ parseJSON json@(Object o) = do
785+ (version :: Text) <- o .: "swagger"
786+ when (version /= "2.0") empty
787+ genericParseJSON (jsonPrefix "swagger") json
790+instance FromJSON SwaggerSecurityScheme where
791+ parseJSON = genericParseJSONWithSub "type" (jsonPrefix "swaggerSecurityScheme")
793+instance FromJSON SwaggerSchema where
794+ parseJSON = genericParseJSONWithSub "common" (jsonPrefix "swaggerSchema")
796+instance FromJSON SwaggerHeader where
797+ parseJSON = genericParseJSONWithSub "common" (jsonPrefix "swaggerHeader")
799+instance FromJSON SwaggerItems where
800+ parseJSON = genericParseJSONWithSub "common" (jsonPrefix "swaggerItems")
802+instance FromJSON SwaggerHost where
803+ parseJSON (String s) =
804+ case fromInteger <$> readMaybe portStr of
805+ Nothing | not (null portStr) -> empty
806+ mport -> pure $ SwaggerHost host mport
808+ (hostText, portText) = Text.breakOnEnd ":" s
809+ [host, portStr] = map Text.unpack [hostText, portText]
812+instance FromJSON SwaggerPaths where
813+ parseJSON json = SwaggerPaths <$> parseJSON json
815+instance FromJSON SwaggerMimeList where
816+ parseJSON json = (SwaggerMimeList . map fromString) <$> parseJSON json
818+instance FromJSON SwaggerParameter where
819+ parseJSON = genericParseJSONWithSub "schema" (jsonPrefix "swaggerParameter")
821+instance FromJSON SwaggerParameterSchema where
822+ parseJSON json@(Object o) = do
823+ (i :: Text) <- o .: "in"
825+ "body" -> SwaggerParameterBody <$> parseJSON json
826+ _ -> SwaggerParameterOther <$> parseJSON json
829+instance FromJSON SwaggerParameterOtherSchema where
830+ parseJSON = genericParseJSONWithSub "common" (jsonPrefix "swaggerParameterOtherSchema")
832+instance FromJSON SwaggerSchemaItems where
833+ parseJSON json@(Object _) = SwaggerSchemaItemsObject <$> parseJSON json
834+ parseJSON json@(Array _) = SwaggerSchemaItemsArray <$> parseJSON json
837+instance FromJSON SwaggerResponses where
838+ parseJSON (Object o) = SwaggerResponses
840+ <*> (parseJSON (Object (HashMap.delete "default" o)) >>= hashMapReadKeys)
843+instance FromJSON SwaggerExample where
846+ pure $ SwaggerExample (Map.mapKeys fromString m)
848+instance FromJSON SwaggerSecurityRequirement where
851+ SwaggerSecurityRequirement <$> hashMapTraverseKeys swaggerSecuritySchemeTypeNameFromText m