@@ -1,4 +1,5 @@
11{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DataKinds #-}
23{-# LANGUAGE DeriveDataTypeable #-}
34{-# LANGUAGE DeriveFunctor #-}
45{-# LANGUAGE DeriveGeneric #-}
@@ -11,19 +12,23 @@
1112{-# LANGUAGE RecordWildCards #-}
1213{-# LANGUAGE ScopedTypeVariables #-}
1314{-# LANGUAGE StandaloneDeriving #-}
15+{-# LANGUAGE TemplateHaskell #-}
16+{-# LANGUAGE TypeFamilies #-}
1417{-# LANGUAGE UndecidableInstances #-}
18+#if __GLASGOW_HASKELL__ <710
19+{-# LANGUAGE PolyKinds #-}
20+#endif
1521#include "overlapping-compat.h"
1622module Data.Swagger.Internal where
1723
1824import Prelude ()
1925import Prelude.Compat
2026
27+import Control.Lens ((&), (.~), (?~))
2128import Control.Applicative
22−import Control.Monad
2329import Data.Aeson
2430import qualified Data.Aeson.Types as JSON
2531import Data.Data (Data(..), Typeable, mkConstr, mkDataType, Fixity(..), Constr, DataType, constrIndex)
26−import Data.HashMap.Strict (HashMap)
2732import qualified Data.HashMap.Strict as HashMap
2833import Data.Map (Map)
2934import qualified Data.Map as Map
@@ -38,10 +43,29 @@ import Network (HostName, PortNumber)
3843import Network.HTTP.Media (MediaType)
3944import Text.Read (readMaybe)
4045
46+import Data.HashMap.Strict.InsOrd (InsOrdHashMap)
47+import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
48+
49+import Generics.SOP.TH (deriveGeneric)
50+import Data.Swagger.Internal.AesonUtils (sopSwaggerGenericToJSON
51+ ,sopSwaggerGenericToJSONWithOpts
52+ ,sopSwaggerGenericParseJSON
53+ ,HasSwaggerAesonOptions(..)
54+ ,AesonDefaultValue(..)
55+ ,mkSwaggerAesonOptions
56+ ,saoAdditionalPairs
57+ ,saoSubObject)
4158import Data.Swagger.Internal.Utils
4259
60+#if MIN_VERSION_aeson(0,10,0)
61+import Data.Swagger.Internal.AesonUtils (sopSwaggerGenericToEncoding)
62+#define DEFINE_TOENCODING toEncoding = sopSwaggerGenericToEncoding
63+#else
64+#define DEFINE_TOENCODING
65+#endif
66+
4367-- | A list of definitions that can be used in references.
44−type Definitions = HashMap Text
68+type Definitions = InsOrdHashMap Text
4569
4670-- | This is the root document object for the API specification.
4771data Swagger = Swagger
@@ -73,7 +97,7 @@ data Swagger = Swagger
7397 -- | The available paths and operations for the API.
7498 -- Holds the relative paths to the individual endpoints.
7599 -- The path is appended to the @'basePath'@ in order to construct the full URL.
76− , _swaggerPaths :: HashMap FilePath PathItem
100+ , _swaggerPaths :: InsOrdHashMap FilePath PathItem
77101
78102 -- | An object to hold data types produced and consumed by operations.
79103 , _swaggerDefinitions :: Definitions Schema
@@ -330,8 +354,8 @@ data ParamOtherSchema = ParamOtherSchema
330354 -- Default value is @False@.
331355 , _paramOtherSchemaAllowEmptyValue :: Maybe Bool
332356
333− , _paramOtherSchemaParamSchema :: ParamSchema ParamOtherSchema
334− } deriving (Eq, Show, Generic, Data, Typeable)
357+ , _paramOtherSchemaParamSchema :: ParamSchema 'SwaggerKindParamOtherSchema
358+ } deriving (Eq, Show, Generic, Typeable, Data)
335359
336360-- | Items for @'SwaggerArray'@ schemas.
337361--
@@ -344,9 +368,9 @@ data ParamOtherSchema = ParamOtherSchema
344368--
345369-- @'SwaggerItemsArray'@ should be used to specify tuple @'Schema'@s.
346370data SwaggerItems t where
347− SwaggerItemsPrimitive :: Maybe (CollectionFormat t) -> ParamSchema t -> SwaggerItems t
348− SwaggerItemsObject :: Referenced Schema -> SwaggerItems Schema
349− SwaggerItemsArray :: [Referenced Schema] -> SwaggerItems Schema
371+ SwaggerItemsPrimitive :: Maybe (CollectionFormat k) -> ParamSchema k-> SwaggerItems k
372+ SwaggerItemsObject :: Referenced Schema -> SwaggerItems 'SwaggerKindSchema
373+ SwaggerItemsArray :: [Referenced Schema] -> SwaggerItems 'SwaggerKindSchema
350374 deriving (Typeable)
351375
352376deriving instance Eq (SwaggerItems t)
@@ -356,17 +380,66 @@ deriving instance Show (SwaggerItems t)
356380swaggerItemsPrimitiveConstr :: Constr
357381swaggerItemsPrimitiveConstr = mkConstr swaggerItemsDataType "SwaggerItemsPrimitive" [] Prefix
358382
383+swaggerItemsObjectConstr :: Constr
384+swaggerItemsObjectConstr = mkConstr swaggerItemsDataType "SwaggerItemsObject" [] Prefix
385+
386+swaggerItemsArrayConstr :: Constr
387+swaggerItemsArrayConstr = mkConstr swaggerItemsDataType "SwaggerItemsArray" [] Prefix
388+
359389swaggerItemsDataType :: DataType
360390swaggerItemsDataType = mkDataType "Data.Swagger.SwaggerItems" [swaggerItemsPrimitiveConstr]
361391
362−instance OVERLAPPABLE_ Data t => Data (SwaggerItems t) where
392+-- Note: unfortunately we have to write these Data instances by hand,
393+-- to get better contexts / avoid duplicate name when using standalone deriving
394+
395+instance Data t => Data (SwaggerItems ('SwaggerKindNormal t)) where
396+ -- TODO: define gfoldl
363397 gunfold k z c = case constrIndex c of
364398 1 -> k (k (z SwaggerItemsPrimitive))
365399 _ -> error $ "Data.Data.gunfold: Constructor " ++ show c ++ " is not of type (SwaggerItems t)."
366400 toConstr _ = swaggerItemsPrimitiveConstr
367401 dataTypeOf _ = swaggerItemsDataType
368402
369−deriving instance Data (SwaggerItems Schema)
403+-- SwaggerItems SwaggerKindParamOtherSchema can be constructed using SwaggerItemsPrimitive only
404+instance Data (SwaggerItems 'SwaggerKindParamOtherSchema) where
405+ -- TODO: define gfoldl
406+ gunfold k z c = case constrIndex c of
407+ 1 -> k (k (z SwaggerItemsPrimitive))
408+ _ -> error $ "Data.Data.gunfold: Constructor " ++ show c ++ " is not of type (SwaggerItems SwaggerKindParamOtherSchema)."
409+ toConstr _ = swaggerItemsPrimitiveConstr
410+ dataTypeOf _ = swaggerItemsDataType
411+
412+instance Data (SwaggerItems 'SwaggerKindSchema) where
413+ gfoldl _ _ (SwaggerItemsPrimitive _ _) = error $ " Data.Data.gfoldl: Constructor SwaggerItemsPrimitive used to construct SwaggerItems SwaggerKindSchema"
414+ gfoldl k z (SwaggerItemsObject ref) = z SwaggerItemsObject `k` ref
415+ gfoldl k z (SwaggerItemsArray ref) = z SwaggerItemsArray `k` ref
416+
417+ gunfold k z c = case constrIndex c of
418+ 2 -> k (z SwaggerItemsObject)
419+ 3 -> k (z SwaggerItemsArray)
420+ _ -> error $ "Data.Data.gunfold: Constructor " ++ show c ++ " is not of type (SwaggerItems SwaggerKindSchema)."
421+
422+ toConstr (SwaggerItemsPrimitive _ _) = error "Not supported"
423+ toConstr (SwaggerItemsObject _) = swaggerItemsObjectConstr
424+ toConstr (SwaggerItemsArray _) = swaggerItemsArrayConstr
425+
426+ dataTypeOf _ = swaggerItemsDataType
427+
428+-- | Type used as a kind to avoid overlapping instances.
429+data SwaggerKind t
430+ = SwaggerKindNormal t
431+ | SwaggerKindParamOtherSchema
432+ | SwaggerKindSchema
433+ deriving (Typeable)
434+
435+deriving instance Typeable 'SwaggerKindNormal
436+deriving instance Typeable 'SwaggerKindParamOtherSchema
437+deriving instance Typeable 'SwaggerKindSchema
438+
439+type family SwaggerKindType (k :: SwaggerKind *) :: *
440+type instance SwaggerKindType ('SwaggerKindNormal t) = t
441+type instance SwaggerKindType 'SwaggerKindSchema = Schema
442+type instance SwaggerKindType 'SwaggerKindParamOtherSchema = ParamOtherSchema
370443
371444data SwaggerType t where
372445 SwaggerString :: SwaggerType t
@@ -374,9 +447,9 @@ data SwaggerType t where
374447 SwaggerInteger :: SwaggerType t
375448 SwaggerBoolean :: SwaggerType t
376449 SwaggerArray :: SwaggerType t
377− SwaggerFile :: SwaggerType ParamOtherSchema
378− SwaggerNull :: SwaggerType Schema
379− SwaggerObject :: SwaggerType Schema
450+ SwaggerFile :: SwaggerType 'SwaggerKindParamOtherSchema
451+ SwaggerNull :: SwaggerType 'SwaggerKindSchema
452+ SwaggerObject :: SwaggerType 'SwaggerKindSchema
380453 deriving (Typeable)
381454
382455deriving instance Eq (SwaggerType t)
@@ -388,30 +461,30 @@ swaggerTypeConstr t = mkConstr (dataTypeOf t) (show t) [] Prefix
388461swaggerTypeDataType :: Data (SwaggerType t) => SwaggerType t -> DataType
389462swaggerTypeDataType _ = mkDataType "Data.Swagger.SwaggerType" swaggerTypeConstrs
390463
391−swaggerCommonTypes :: [SwaggerType t]
464+swaggerCommonTypes :: [SwaggerType k]
392465swaggerCommonTypes = [SwaggerString, SwaggerNumber, SwaggerInteger, SwaggerBoolean, SwaggerArray]
393466
394−swaggerParamTypes :: [SwaggerType ParamOtherSchema]
467+swaggerParamTypes :: [SwaggerType 'SwaggerKindParamOtherSchema]
395468swaggerParamTypes = swaggerCommonTypes ++ [SwaggerFile]
396469
397−swaggerSchemaTypes :: [SwaggerType Schema]
470+swaggerSchemaTypes :: [SwaggerType 'SwaggerKindSchema]
398471swaggerSchemaTypes = swaggerCommonTypes ++ [error "SwaggerFile is invalid SwaggerType Schema", SwaggerNull, SwaggerObject]
399472
400473swaggerTypeConstrs :: [Constr]
401−swaggerTypeConstrs = map swaggerTypeConstr (swaggerCommonTypes :: [SwaggerType Schema])
474+swaggerTypeConstrs = map swaggerTypeConstr (swaggerCommonTypes :: [SwaggerType 'SwaggerKindSchema])
402475 ++ [swaggerTypeConstr SwaggerFile, swaggerTypeConstr SwaggerNull, swaggerTypeConstr SwaggerObject]
403476
404−instance OVERLAPPABLE_ Typeable t => Data (SwaggerType t) where
477+instance Typeable t => Data (SwaggerType ('SwaggerKindNormal t)) where
405478 gunfold = gunfoldEnum "SwaggerType" swaggerCommonTypes
406479 toConstr = swaggerTypeConstr
407480 dataTypeOf = swaggerTypeDataType
408481
409−instance OVERLAPPABLE_ Data (SwaggerType ParamOtherSchema) where
482+instance Data (SwaggerType 'SwaggerKindParamOtherSchema) where
410483 gunfold = gunfoldEnum "SwaggerType ParamOtherSchema" swaggerParamTypes
411484 toConstr = swaggerTypeConstr
412485 dataTypeOf = swaggerTypeDataType
413486
414−instance OVERLAPPABLE_ Data (SwaggerType Schema) where
487+instance Data (SwaggerType 'SwaggerKindSchema) where
415488 gunfold = gunfoldEnum "SwaggerType Schema" swaggerSchemaTypes
416489 toConstr = swaggerTypeConstr
417490 dataTypeOf = swaggerTypeDataType
@@ -451,7 +524,7 @@ data CollectionFormat t where
451524 -- Corresponds to multiple parameter instances
452525 -- instead of multiple values for a single instance @foo=bar&foo=baz@.
453526 -- This is valid only for parameters in @'ParamQuery'@ or @'ParamFormData'@.
454− CollectionMulti :: CollectionFormat ParamOtherSchema
527+ CollectionMulti :: CollectionFormat 'SwaggerKindParamOtherSchema
455528 deriving (Typeable)
456529
457530deriving instance Eq (CollectionFormat t)
@@ -467,12 +540,12 @@ collectionFormatDataType = mkDataType "Data.Swagger.CollectionFormat" $
467540collectionCommonFormats :: [CollectionFormat t]
468541collectionCommonFormats = [ CollectionCSV, CollectionSSV, CollectionTSV, CollectionPipes ]
469542
470−instance OVERLAPPABLE_ Data t => Data (CollectionFormat t) where
543+instance Data t => Data (CollectionFormat ('SwaggerKindNormal t)) where
471544 gunfold = gunfoldEnum "CollectionFormat" collectionCommonFormats
472545 toConstr = collectionFormatConstr
473546 dataTypeOf _ = collectionFormatDataType
474547
475−deriving instance OVERLAPPABLE_ Data (CollectionFormat ParamOtherSchema)
548+deriving instance Data (CollectionFormat 'SwaggerKindParamOtherSchema)
476549
477550type ParamName = Text
478551
@@ -482,7 +555,7 @@ data Schema = Schema
482555 , _schemaRequired :: [ParamName]
483556
484557 , _schemaAllOf :: Maybe [Schema]
485− , _schemaProperties :: HashMap Text (Referenced Schema)
558+ , _schemaProperties :: InsOrdHashMap Text (Referenced Schema)
486559 , _schemaAdditionalProperties :: Maybe (Referenced Schema)
487560
488561 , _schemaDiscriminator :: Maybe Text
@@ -494,7 +567,7 @@ data Schema = Schema
494567 , _schemaMaxProperties :: Maybe Integer
495568 , _schemaMinProperties :: Maybe Integer
496569
497− , _schemaParamSchema :: ParamSchema Schema
570+ , _schemaParamSchema :: ParamSchema 'SwaggerKindSchema
498571 } deriving (Eq, Show, Generic, Data, Typeable)
499572
500573-- | A @'Schema'@ with an optional name.
@@ -507,7 +580,7 @@ data NamedSchema = NamedSchema
507580-- | Regex pattern for @string@ type.
508581type Pattern = Text
509582
510−data ParamSchema t = ParamSchema
583+data ParamSchema (t :: SwaggerKind *) = ParamSchema
511584 { -- | Declares the value of the parameter that the server will use if none is provided,
512585 -- for example a @"count"@ to control the number of results per page might default to @100@
513586 -- if not supplied by the client in the request.
@@ -532,7 +605,7 @@ data ParamSchema t = ParamSchema
532605 , _paramSchemaMultipleOf :: Maybe Scientific
533606 } deriving (Eq, Show, Generic, Typeable)
534607
535−deriving instance (Data t, Data (SwaggerType t), Data (SwaggerItems t)) => Data (ParamSchema t)
608+deriving instance (Typeable k, Data (SwaggerKindType k), Data (SwaggerType k), Data (SwaggerItems k)) => Data (ParamSchema k)
536609
537610data Xml = Xml
538611 { -- | Replaces the name of the element/attribute used for the described schema property.
@@ -574,7 +647,7 @@ data Responses = Responses
574647
575648 -- | Any HTTP status code can be used as the property name (one property per HTTP status code).
576649 -- Describes the expected response for those HTTP status codes.
577− , _responsesResponses :: HashMap HttpStatusCode (Referenced Response)
650+ , _responsesResponses :: InsOrdHashMap HttpStatusCode (Referenced Response)
578651 } deriving (Eq, Show, Generic, Data, Typeable)
579652
580653type HttpStatusCode = Int
@@ -593,7 +666,7 @@ data Response = Response
593666 , _responseSchema :: Maybe (Referenced Schema)
594667
595668 -- | A list of headers that are sent with the response.
596− , _responseHeaders :: HashMap HeaderName Header
669+ , _responseHeaders :: InsOrdHashMap HeaderName Header
597670
598671 -- | An example of the response message.
599672 , _responseExamples :: Maybe Example
@@ -608,7 +681,7 @@ data Header = Header
608681 { -- | A short description of the header.
609682 _headerDescription :: Maybe Text
610683
611− , _headerParamSchema :: ParamSchema Header
684+ , _headerParamSchema :: ParamSchema ('SwaggerKindNormal Header)
612685 } deriving (Eq, Show, Generic, Data, Typeable)
613686
614687data Example = Example { getExample :: Map MediaType Value }
@@ -659,7 +732,7 @@ data OAuth2Params = OAuth2Params
659732 _oauth2Flow :: OAuth2Flow
660733
661734 -- | The available scopes for the OAuth2 security scheme.
662− , _oauth2Scopes :: HashMap Text Text
735+ , _oauth2Scopes :: InsOrdHashMap Text Text
663736 } deriving (Eq, Show, Generic, Data, Typeable)
664737
665738data SecuritySchemeType
@@ -680,7 +753,7 @@ data SecurityScheme = SecurityScheme
680753-- The object can have multiple security schemes declared in it which are all required
681754-- (that is, there is a logical AND between the schemes).
682755newtype SecurityRequirement = SecurityRequirement
683− { getSecurityRequirement :: HashMap Text [Text]
756+ { getSecurityRequirement :: InsOrdHashMap Text [Text]
684757 } deriving (Eq, Read, Show, Monoid, ToJSON, FromJSON, Data, Typeable)
685758
686759-- | Tag name.
@@ -814,9 +887,9 @@ instance SwaggerMonoid ParamLocation where
814887 swaggerMempty = ParamQuery
815888 swaggerMappend _ y = y
816889
817−instance OVERLAPPING_ SwaggerMonoid (HashMap FilePath PathItem) where
818− swaggerMempty = HashMap.empty
819− swaggerMappend = HashMap.unionWith mappend
890+instance OVERLAPPING_ SwaggerMonoid (InsOrdHashMap FilePath PathItem) where
891+ swaggerMempty = InsOrdHashMap.empty
892+ swaggerMappend = InsOrdHashMap.unionWith mappend
820893
821894instance Monoid a => SwaggerMonoid (Referenced a) where
822895 swaggerMempty = Inline mempty
@@ -914,7 +987,8 @@ instance ToJSON OAuth2Flow where
914987 , "tokenUrl" .= tokenUrl ]
915988
916989instance ToJSON OAuth2Params where
917− toJSON = omitEmpties . genericToJSONWithSub "flow" (jsonPrefix "oauth2")
990+ toJSON = sopSwaggerGenericToJSON
991+ DEFINE_TOENCODING
918992
919993instance ToJSON SecuritySchemeType where
920994 toJSON SecuritySchemeBasic
@@ -927,24 +1001,22 @@ instance ToJSON SecuritySchemeType where
9271001 <+> object [ "type" .= ("oauth2" :: Text) ]
9281002
9291003instance ToJSON Swagger where
930− toJSON = omitEmpties . addVersion . genericToJSON (jsonPrefix "swagger")
931− where
932− addVersion (Object o) = Object (HashMap.insert "swagger" "2.0" o)
933− addVersion _ = error "impossible"
1004+ toJSON = sopSwaggerGenericToJSON
1005+ DEFINE_TOENCODING
9341006
9351007instance ToJSON SecurityScheme where
936− toJSON = genericToJSONWithSub "type" (jsonPrefix "securityScheme")
1008+ toJSON = sopSwaggerGenericToJSON
1009+ DEFINE_TOENCODING
9371010
9381011instance ToJSON Schema where
939− toJSON = omitEmptiesExcept f . genericToJSONWithSub "paramSchema" (jsonPrefix "schema")
940− where
941− f "items" (Array _) = True
942− f _ _ = False
1012+ toJSON = sopSwaggerGenericToJSON
1013+ DEFINE_TOENCODING
9431014
9441015instance ToJSON Header where
945− toJSON = genericToJSONWithSub "paramSchema" (jsonPrefix "header")
1016+ toJSON = sopSwaggerGenericToJSON
1017+ DEFINE_TOENCODING
9461018
947−instance ToJSON (SwaggerItems t) where
1019+instance ToJSON (ParamSchema t) => ToJSON (SwaggerItems t) where
9481020 toJSON (SwaggerItemsPrimitive fmt schema) = object
9491021 [ "collectionFormat" .= fmt
9501022 , "items" .= schema ]
@@ -961,27 +1033,32 @@ instance ToJSON MimeList where
9611033 toJSON (MimeList xs) = toJSON (map show xs)
9621034
9631035instance ToJSON Param where
964− toJSON = genericToJSONWithSub "schema" (jsonPrefix "param")
1036+ toJSON = sopSwaggerGenericToJSON
1037+ DEFINE_TOENCODING
9651038
9661039instance ToJSON ParamAnySchema where
9671040 toJSON (ParamBody s) = object [ "in" .= ("body" :: Text), "schema" .= s ]
9681041 toJSON (ParamOther s) = toJSON s
9691042
9701043instance ToJSON ParamOtherSchema where
971− toJSON = genericToJSONWithSub "paramSchema" (jsonPrefix "paramOtherSchema")
1044+ toJSON = sopSwaggerGenericToJSON
1045+ DEFINE_TOENCODING
9721046
9731047instance ToJSON Responses where
974− toJSON (Responses def rs) = omitEmpties $
975− toJSON (hashMapMapKeys show rs) <+> object [ "default" .= def ]
1048+ toJSON = sopSwaggerGenericToJSON
1049+ DEFINE_TOENCODING
9761050
9771051instance ToJSON Response where
978− toJSON = omitEmpties . genericToJSON (jsonPrefix "response")
1052+ toJSON = sopSwaggerGenericToJSON
1053+ DEFINE_TOENCODING
9791054
9801055instance ToJSON Operation where
981− toJSON = omitEmpties . genericToJSON (jsonPrefix "operation")
1056+ toJSON = sopSwaggerGenericToJSON
1057+ DEFINE_TOENCODING
9821058
9831059instance ToJSON PathItem where
984− toJSON = omitEmpties . genericToJSON (jsonPrefix "pathItem")
1060+ toJSON = sopSwaggerGenericToJSON
1061+ DEFINE_TOENCODING
9851062
9861063instance ToJSON Example where
9871064 toJSON = toJSON . Map.mapKeys show . getExample
@@ -1014,11 +1091,10 @@ instance ToJSON (CollectionFormat t) where
10141091 toJSON CollectionPipes = "pipes"
10151092 toJSON CollectionMulti = "multi"
10161093
1017−instance ToJSON (ParamSchema t) where
1018− toJSON = omitEmptiesExcept f . genericToJSONWithSub "items" (jsonPrefix "paramSchema")
1019− where
1020− f "items" (Array _) = True
1021− f _ _ = False
1094+instance ToJSON (ParamSchema k) where
1095+ -- TODO: this is a bit fishy, why we need sub object only in `ToJSON`?
1096+ toJSON = sopSwaggerGenericToJSONWithOpts $
1097+ mkSwaggerAesonOptions "paramSchema" & saoSubObject ?~ "items"
10221098
10231099-- =======================================================================
10241100-- Manual FromJSON instances
@@ -1038,7 +1114,7 @@ instance FromJSON OAuth2Flow where
10381114 parseJSON _ = empty
10391115
10401116instance FromJSON OAuth2Params where
1041− parseJSON = genericParseJSONWithSub "flow" (jsonPrefix "oauth2")
1117+ parseJSON = sopSwaggerGenericParseJSON
10421118
10431119instance FromJSON SecuritySchemeType where
10441120 parseJSON js@(Object o) = do
@@ -1051,38 +1127,28 @@ instance FromJSON SecuritySchemeType where
10511127 parseJSON _ = empty
10521128
10531129instance FromJSON Swagger where
1054− parseJSON js@(Object o) = do
1055− (version :: Text) <- o .: "swagger"
1056− when (version /= "2.0") empty
1057− (genericParseJSON (jsonPrefix "swagger")
1058− `withDefaults` [ "consumes" .= (mempty :: MimeList)
1059− , "produces" .= (mempty :: MimeList)
1060− , "security" .= ([] :: [SecurityRequirement])
1061− , "tags" .= ([] :: [Tag])
1062− , "definitions" .= (mempty :: Definitions Schema)
1063− , "parameters" .= (mempty :: Definitions Param)
1064− , "responses" .= (mempty :: Definitions Response)
1065− , "securityDefinitions" .= (mempty :: Definitions SecurityScheme)
1066− ] ) js
1067− parseJSON _ = empty
1130+ parseJSON = sopSwaggerGenericParseJSON
10681131
10691132instance FromJSON SecurityScheme where
1070− parseJSON = genericParseJSONWithSub "type" (jsonPrefix "securityScheme")
1133+ parseJSON = sopSwaggerGenericParseJSON
10711134
10721135instance FromJSON Schema where
1073− parseJSON = genericParseJSONWithSub "paramSchema" (jsonPrefix "schema")
1074− `withDefaults` [ "properties" .= (mempty :: HashMap Text Schema)
1075− , "required" .= ([] :: [ParamName]) ]
1136+ parseJSON = sopSwaggerGenericParseJSON
10761137
10771138instance FromJSON Header where
1078− parseJSON = genericParseJSONWithSub "paramSchema" (jsonPrefix "header")
1139+ parseJSON = sopSwaggerGenericParseJSON
10791140
1080−instance OVERLAPPABLE_ (FromJSON (CollectionFormat t), FromJSON (ParamSchema t)) => FromJSON (SwaggerItems t) where
1141+instance (FromJSON (CollectionFormat ('SwaggerKindNormal t)), FromJSON (ParamSchema ('SwaggerKindNormal t))) => FromJSON (SwaggerItems ('SwaggerKindNormal t)) where
10811142 parseJSON = withObject "SwaggerItemsPrimitive" $ \o -> SwaggerItemsPrimitive
10821143 <$> o .:? "collectionFormat"
10831144 <*> (o .: "items" >>= parseJSON)
10841145
1085−instance OVERLAPPABLE_ FromJSON (SwaggerItems Schema) where
1146+instance FromJSON (SwaggerItems 'SwaggerKindParamOtherSchema) where
1147+ parseJSON = withObject "SwaggerItemsPrimitive" $ \o -> SwaggerItemsPrimitive
1148+ <$> o .:? "collectionFormat"
1149+ <*> ((o .: "items" >>= parseJSON) <|> fail ("foo" ++ show o))
1150+
1151+instance FromJSON (SwaggerItems 'SwaggerKindSchema) where
10861152 parseJSON js@(Object _) = SwaggerItemsObject <$> parseJSON js
10871153 parseJSON js@(Array _) = SwaggerItemsArray <$> parseJSON js
10881154 parseJSON _ = empty
@@ -1100,7 +1166,7 @@ instance FromJSON MimeList where
11001166 parseJSON js = (MimeList . map fromString) <$> parseJSON js
11011167
11021168instance FromJSON Param where
1103− parseJSON = genericParseJSONWithSub "schema" (jsonPrefix "param")
1169+ parseJSON = sopSwaggerGenericParseJSON
11041170
11051171instance FromJSON ParamAnySchema where
11061172 parseJSON js@(Object o) = do
@@ -1113,12 +1179,12 @@ instance FromJSON ParamAnySchema where
11131179 parseJSON _ = empty
11141180
11151181instance FromJSON ParamOtherSchema where
1116− parseJSON = genericParseJSONWithSub "paramSchema" (jsonPrefix "paramOtherSchema")
1182+ parseJSON = sopSwaggerGenericParseJSON
11171183
11181184instance FromJSON Responses where
11191185 parseJSON (Object o) = Responses
11201186 <$> o .:? "default"
1121− <*> (parseJSON (Object (HashMap.delete "default" o)) >>= hashMapReadKeys)
1187+ <*> (parseJSON (Object (HashMap.delete "default" o)))
11221188 parseJSON _ = empty
11231189
11241190instance FromJSON Example where
@@ -1127,18 +1193,13 @@ instance FromJSON Example where
11271193 pure $ Example (Map.mapKeys fromString m)
11281194
11291195instance FromJSON Response where
1130− parseJSON = genericParseJSON (jsonPrefix "response")
1131− `withDefaults` [ "headers" .= (mempty :: HashMap HeaderName Header) ]
1196+ parseJSON = sopSwaggerGenericParseJSON
11321197
11331198instance FromJSON Operation where
1134− parseJSON = genericParseJSON (jsonPrefix "operation")
1135− `withDefaults` [ "security" .= ([] :: [SecurityRequirement])
1136− , "tags" .= ([] :: [Tag])
1137− , "parameters" .= ([] :: [Referenced Param]) ]
1199+ parseJSON = sopSwaggerGenericParseJSON
11381200
11391201instance FromJSON PathItem where
1140− parseJSON = genericParseJSON (jsonPrefix "pathItem")
1141− `withDefaults` [ "parameters" .= ([] :: [Param]) ]
1202+ parseJSON = sopSwaggerGenericParseJSON
11421203
11431204instance FromJSON Reference where
11441205 parseJSON (Object o) = Reference <$> o .: "$ref"
@@ -1164,26 +1225,86 @@ instance FromJSON (Referenced Response) where parseJSON = referencedParseJSON "#
11641225instance FromJSON Xml where
11651226 parseJSON = genericParseJSON (jsonPrefix "xml")
11661227
1167−instance FromJSON (SwaggerType Schema) where
1228+instance FromJSON (SwaggerType 'SwaggerKindSchema) where
11681229 parseJSON = parseOneOf [SwaggerString, SwaggerInteger, SwaggerNumber, SwaggerBoolean, SwaggerArray, SwaggerNull, SwaggerObject]
11691230
1170−instance FromJSON (SwaggerType ParamOtherSchema) where
1231+instance FromJSON (SwaggerType 'SwaggerKindParamOtherSchema) where
11711232 parseJSON = parseOneOf [SwaggerString, SwaggerInteger, SwaggerNumber, SwaggerBoolean, SwaggerArray, SwaggerFile]
11721233
1173−instance OVERLAPPABLE_ FromJSON (SwaggerType t) where
1234+instance FromJSON (SwaggerType ('SwaggerKindNormal t)) where
11741235 parseJSON = parseOneOf [SwaggerString, SwaggerInteger, SwaggerNumber, SwaggerBoolean, SwaggerArray]
11751236
1176−instance OVERLAPPABLE_ FromJSON (CollectionFormat t) where
1237+instance FromJSON (CollectionFormat ('SwaggerKindNormal t)) where
11771238 parseJSON = parseOneOf [CollectionCSV, CollectionSSV, CollectionTSV, CollectionPipes]
11781239
1179−instance FromJSON (CollectionFormat ParamOtherSchema) where
1180− parseJSON = parseOneOf [CollectionCSV, CollectionSSV, CollectionTSV, CollectionPipes, CollectionMulti]
1240+-- NOTE: There aren't collections of 'Schema'
1241+--instance FromJSON (CollectionFormat (SwaggerKindSchema)) where
1242+-- parseJSON = parseOneOf [CollectionCSV, CollectionSSV, CollectionTSV, CollectionPipes]
11811243
1182−-- NOTE: The constraints @FromJSON (SwaggerType t)@ and
1183−-- @FromJSON (SwaggerItems t)@ are necessary here!
1184−-- Without the constraint the general instance will be used
1185−-- that only accepts common types (i.e. NOT object, null or file)
1186−-- and primitive array items.
1187−instance (FromJSON (SwaggerType t), FromJSON (SwaggerItems t)) => FromJSON (ParamSchema t) where
1188− parseJSON = genericParseJSONWithSub "items" (jsonPrefix "ParamSchema")
1244+instance FromJSON (CollectionFormat 'SwaggerKindParamOtherSchema) where
1245+ parseJSON = parseOneOf [CollectionCSV, CollectionSSV, CollectionTSV, CollectionPipes, CollectionMulti]
11891246
1247+instance (FromJSON (SwaggerType ('SwaggerKindNormal t)), FromJSON (SwaggerItems ('SwaggerKindNormal t))) => FromJSON (ParamSchema ('SwaggerKindNormal t)) where
1248+ parseJSON = sopSwaggerGenericParseJSON
1249+instance FromJSON (ParamSchema 'SwaggerKindParamOtherSchema) where
1250+ parseJSON = sopSwaggerGenericParseJSON
1251+instance FromJSON (ParamSchema 'SwaggerKindSchema) where
1252+ parseJSON = sopSwaggerGenericParseJSON
1253+
1254+-------------------------------------------------------------------------------
1255+-- TH splices
1256+-------------------------------------------------------------------------------
1257+
1258+deriveGeneric ''Header
1259+deriveGeneric ''OAuth2Params
1260+deriveGeneric ''Operation
1261+deriveGeneric ''Param
1262+deriveGeneric ''ParamOtherSchema
1263+deriveGeneric ''PathItem
1264+deriveGeneric ''Response
1265+deriveGeneric ''Responses
1266+deriveGeneric ''SecurityScheme
1267+deriveGeneric ''Schema
1268+deriveGeneric ''ParamSchema
1269+deriveGeneric ''Swagger
1270+
1271+instance HasSwaggerAesonOptions Header where
1272+ swaggerAesonOptions _ = mkSwaggerAesonOptions "header" & saoSubObject ?~ "paramSchema"
1273+instance HasSwaggerAesonOptions OAuth2Params where
1274+ swaggerAesonOptions _ = mkSwaggerAesonOptions "oauth2" & saoSubObject ?~ "flow"
1275+instance HasSwaggerAesonOptions Operation where
1276+ swaggerAesonOptions _ = mkSwaggerAesonOptions "operation"
1277+instance HasSwaggerAesonOptions Param where
1278+ swaggerAesonOptions _ = mkSwaggerAesonOptions "param" & saoSubObject ?~ "schema"
1279+instance HasSwaggerAesonOptions ParamOtherSchema where
1280+ swaggerAesonOptions _ = mkSwaggerAesonOptions "paramOtherSchema" & saoSubObject ?~ "paramSchema"
1281+instance HasSwaggerAesonOptions PathItem where
1282+ swaggerAesonOptions _ = mkSwaggerAesonOptions "pathItem"
1283+instance HasSwaggerAesonOptions Response where
1284+ swaggerAesonOptions _ = mkSwaggerAesonOptions "response"
1285+instance HasSwaggerAesonOptions Responses where
1286+ swaggerAesonOptions _ = mkSwaggerAesonOptions "responses" & saoSubObject ?~ "responses"
1287+instance HasSwaggerAesonOptions SecurityScheme where
1288+ swaggerAesonOptions _ = mkSwaggerAesonOptions "securityScheme" & saoSubObject ?~ "type"
1289+instance HasSwaggerAesonOptions Schema where
1290+ swaggerAesonOptions _ = mkSwaggerAesonOptions "schema" & saoSubObject ?~ "paramSchema"
1291+instance HasSwaggerAesonOptions Swagger where
1292+ swaggerAesonOptions _ = mkSwaggerAesonOptions "swagger" & saoAdditionalPairs .~ [("swagger", "2.0")]
1293+
1294+instance HasSwaggerAesonOptions (ParamSchema ('SwaggerKindNormal t)) where
1295+ swaggerAesonOptions _ = mkSwaggerAesonOptions "paramSchema" & saoSubObject ?~ "items"
1296+instance HasSwaggerAesonOptions (ParamSchema 'SwaggerKindParamOtherSchema) where
1297+ swaggerAesonOptions _ = mkSwaggerAesonOptions "paramSchema" & saoSubObject ?~ "items"
1298+-- NOTE: Schema doesn't have 'items' sub object!
1299+instance HasSwaggerAesonOptions (ParamSchema 'SwaggerKindSchema) where
1300+ swaggerAesonOptions _ = mkSwaggerAesonOptions "paramSchema"
1301+
1302+instance AesonDefaultValue (ParamSchema s)
1303+instance AesonDefaultValue OAuth2Flow
1304+instance AesonDefaultValue Responses
1305+instance AesonDefaultValue ParamAnySchema
1306+instance AesonDefaultValue SecuritySchemeType
1307+instance AesonDefaultValue (SwaggerType a)
1308+instance AesonDefaultValue MimeList where defaultValue = Just mempty
1309+instance AesonDefaultValue Info
1310+instance AesonDefaultValue ParamLocation