@@ -32,7 +32,7 @@ import Data.Data.Lens (template)
3232
3333import Control.Monad
3434import Control.Monad.Writer
35−import Data.Aeson
35+import Data.Aeson (ToJSON (..), ToJSONKey (..), ToJSONKeyFunction (..), Value (..), Object(..))
3636import Data.Char
3737import Data.Data (Data)
3838import Data.Foldable (traverse_)
@@ -44,9 +44,11 @@ import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
4444import Data.Int
4545import Data.IntSet (IntSet)
4646import Data.IntMap (IntMap)
47+import Data.List.NonEmpty.Compat (NonEmpty)
4748import Data.Map (Map)
4849import Data.Proxy
4950import Data.Scientific (Scientific)
51+import Data.Fixed (Fixed, HasResolution, Pico)
5052import Data.Set (Set)
5153import qualified Data.Text as T
5254import qualified Data.Text.Lazy as TL
@@ -55,6 +57,8 @@ import qualified Data.Vector as V
5557import qualified Data.Vector.Primitive as VP
5658import qualified Data.Vector.Storable as VS
5759import qualified Data.Vector.Unboxed as VU
60+import Data.Version (Version)
61+import Numeric.Natural.Compat (Natural)
5862import Data.Word
5963import GHC.Generics
6064import qualified Data.UUID.Types as UUID
@@ -107,7 +111,7 @@ rename name (NamedSchema _ schema) = NamedSchema name schema
107111-- declareNamedSchema _ = do
108112-- doubleSchema <- declareSchemaRef (Proxy :: Proxy Double)
109113-- return $ NamedSchema (Just \"Coord\") $ mempty
110−-- & type_ .~ SwaggerObject
114+-- & type_ ?~ SwaggerObject
111115-- & properties .~
112116-- [ (\"x\", doubleSchema)
113117-- , (\"y\", doubleSchema)
@@ -138,13 +142,17 @@ class ToSchema a where
138142 -- together with all used definitions.
139143 -- Note that the schema itself is included in definitions
140144 -- only if it is recursive (and thus needs its definition in scope).
141− declareNamedSchema :: proxy a -> Declare (Definitions Schema) NamedSchema
145+ declareNamedSchema :: Proxy a -> Declare (Definitions Schema) NamedSchema
142146 default declareNamedSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareNamedSchemaUnrestricted") =>
143− proxy a -> Declare (Definitions Schema) NamedSchema
147+ Proxy a -> Declare (Definitions Schema) NamedSchema
144148 declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
145149
150+instance ToSchema TimeOfDay where
151+ declareNamedSchema _ = pure $ named "TimeOfDay" $ timeSchema "hh:MM:ss"
152+ & example ?~ toJSON (TimeOfDay 12 33 15)
153+
146154-- | Convert a type into a schema and declare all used schema definitions.
147−declareSchema :: ToSchema a => proxy a -> Declare (Definitions Schema) Schema
155+declareSchema :: ToSchema a => Proxy a -> Declare (Definitions Schema) Schema
148156declareSchema = fmap _namedSchemaSchema . declareNamedSchema
149157
150158-- | Convert a type into an optionally named schema.
@@ -158,7 +166,7 @@ declareSchema = fmap _namedSchemaSchema . declareNamedSchema
158166-- Just "Day"
159167-- >>> encode (toNamedSchema (Proxy :: Proxy Day) ^. schema)
160168-- "{\"example\":\"2016-07-22\",\"format\":\"date\",\"type\":\"string\"}"
161−toNamedSchema :: ToSchema a => proxy a -> NamedSchema
169+toNamedSchema :: ToSchema a => Proxy a -> NamedSchema
162170toNamedSchema = undeclare . declareNamedSchema
163171
164172-- | Get type's schema name according to its @'ToSchema'@ instance.
@@ -168,7 +176,7 @@ toNamedSchema = undeclare . declareNamedSchema
168176--
169177-- >>> schemaName (Proxy :: Proxy UTCTime)
170178-- Just "UTCTime"
171−schemaName :: ToSchema a => proxy a -> Maybe T.Text
179+schemaName :: ToSchema a => Proxy a -> Maybe T.Text
172180schemaName = _namedSchemaName . toNamedSchema
173181
174182-- | Convert a type into a schema.
@@ -178,7 +186,7 @@ schemaName = _namedSchemaName . toNamedSchema
178186--
179187-- >>> encode $ toSchema (Proxy :: Proxy [Day])
180188-- "{\"items\":{\"$ref\":\"#/definitions/Day\"},\"type\":\"array\"}"
181−toSchema :: ToSchema a => proxy a -> Schema
189+toSchema :: ToSchema a => Proxy a -> Schema
182190toSchema = _namedSchemaSchema . toNamedSchema
183191
184192-- | Convert a type into a referenced schema if possible.
@@ -189,7 +197,7 @@ toSchema = _namedSchemaSchema . toNamedSchema
189197--
190198-- >>> encode $ toSchemaRef (Proxy :: Proxy Day)
191199-- "{\"$ref\":\"#/definitions/Day\"}"
192−toSchemaRef :: ToSchema a => proxy a -> Referenced Schema
200+toSchemaRef :: ToSchema a => Proxy a -> Referenced Schema
193201toSchemaRef = undeclare . declareSchemaRef
194202
195203-- | Convert a type into a referenced schema if possible
@@ -199,7 +207,7 @@ toSchemaRef = undeclare . declareSchemaRef
199207-- Schema definitions are typically declared for every referenced schema.
200208-- If @'declareSchemaRef'@ returns a reference, a corresponding schema
201209-- will be declared (regardless of whether it is recusive or not).
202−declareSchemaRef :: ToSchema a => proxy a -> Declare (Definitions Schema) (Referenced Schema)
210+declareSchemaRef :: ToSchema a => Proxy a -> Declare (Definitions Schema) (Referenced Schema)
203211declareSchemaRef proxy = do
204212 case toNamedSchema proxy of
205213 NamedSchema (Just name) schema -> do
@@ -261,7 +269,7 @@ inlineAllSchemas = inlineSchemasWhen (const True)
261269--
262270-- __WARNING:__ @'toInlinedSchema'@ will produce infinite schema
263271-- when inlining recursive schemas.
264−toInlinedSchema :: ToSchema a => proxy a -> Schema
272+toInlinedSchema :: ToSchema a => Proxy a -> Schema
265273toInlinedSchema proxy = inlineAllSchemas defs schema
266274 where
267275 (defs, schema) = runDeclare (declareSchema proxy) mempty
@@ -290,20 +298,20 @@ inlineNonRecursiveSchemas defs = inlineSchemasWhen nonRecursive defs
290298-- | Default schema for binary data (any sequence of octets).
291299binarySchema :: Schema
292300binarySchema = mempty
293− & type_ .~ SwaggerString
301+ & type_ ?~ SwaggerString
294302 & format ?~ "binary"
295303
296304-- | Default schema for binary data (base64 encoded).
297305byteSchema :: Schema
298306byteSchema = mempty
299− & type_ .~ SwaggerString
307+ & type_ ?~ SwaggerString
300308 & format ?~ "byte"
301309
302310-- | Default schema for password string.
303311-- @"password"@ format is used to hint UIs the input needs to be obscured.
304312passwordSchema :: Schema
305313passwordSchema = mempty
306− & type_ .~ SwaggerString
314+ & type_ ?~ SwaggerString
307315 & format ?~ "password"
308316
309317-- | Make an unrestrictive sketch of a @'Schema'@ based on a @'ToJSON'@ instance.
@@ -329,12 +337,12 @@ sketchSchema = sketch . toJSON
329337 sketch js@(Bool _) = go js
330338 sketch js = go js & example ?~ js
331339
332− go Null = mempty & type_ .~ SwaggerNull
333− go (Bool _) = mempty & type_ .~ SwaggerBoolean
334− go (String _) = mempty & type_ .~ SwaggerString
335− go (Number _) = mempty & type_ .~ SwaggerNumber
340+ go Null = mempty & type_ ?~ SwaggerNull
341+ go (Bool _) = mempty & type_ ?~ SwaggerBoolean
342+ go (String _) = mempty & type_ ?~ SwaggerString
343+ go (Number _) = mempty & type_ ?~ SwaggerNumber
336344 go (Array xs) = mempty
337− & type_ .~ SwaggerArray
345+ & type_ ?~ SwaggerArray
338346 & items ?~ case ischema of
339347 Just s -> SwaggerItemsObject (Inline s)
340348 _ -> SwaggerItemsArray (map Inline ys)
@@ -346,7 +354,7 @@ sketchSchema = sketch . toJSON
346354 (z:_) | allSame -> Just z
347355 _ -> Nothing
348356 go (Object o) = mempty
349− & type_ .~ SwaggerObject
357+ & type_ ?~ SwaggerObject
350358 & required .~ HashMap.keys o
351359 & properties .~ fmap (Inline . go) (InsOrdHashMap.fromHashMap o)
352360
@@ -369,24 +377,24 @@ sketchSchema = sketch . toJSON
369377sketchStrictSchema :: ToJSON a => a -> Schema
370378sketchStrictSchema = go . toJSON
371379 where
372− go Null = mempty & type_ .~ SwaggerNull
380+ go Null = mempty & type_ ?~ SwaggerNull
373381 go js@(Bool _) = mempty
374− & type_ .~ SwaggerBoolean
382+ & type_ ?~ SwaggerBoolean
375383 & enum_ ?~ [js]
376384 go js@(String s) = mempty
377− & type_ .~ SwaggerString
385+ & type_ ?~ SwaggerString
378386 & maxLength ?~ fromIntegral (T.length s)
379387 & minLength ?~ fromIntegral (T.length s)
380388 & pattern ?~ s
381389 & enum_ ?~ [js]
382390 go js@(Number n) = mempty
383− & type_ .~ SwaggerNumber
391+ & type_ ?~ SwaggerNumber
384392 & maximum_ ?~ n
385393 & minimum_ ?~ n
386394 & multipleOf ?~ n
387395 & enum_ ?~ [js]
388396 go js@(Array xs) = mempty
389− & type_ .~ SwaggerArray
397+ & type_ ?~ SwaggerArray
390398 & maxItems ?~ fromIntegral sz
391399 & minItems ?~ fromIntegral sz
392400 & items ?~ SwaggerItemsArray (map (Inline . go) (V.toList xs))
@@ -396,7 +404,7 @@ sketchStrictSchema = go . toJSON
396404 sz = length xs
397405 allUnique = sz == HashSet.size (HashSet.fromList (V.toList xs))
398406 go js@(Object o) = mempty
399− & type_ .~ SwaggerObject
407+ & type_ ?~ SwaggerObject
400408 & required .~ names
401409 & properties .~ fmap (Inline . go) (InsOrdHashMap.fromHashMap o)
402410 & maxProperties ?~ fromIntegral (length names)
@@ -406,18 +414,19 @@ sketchStrictSchema = go . toJSON
406414 names = HashMap.keys o
407415
408416class GToSchema (f :: * -> *) where
409− gdeclareNamedSchema :: SchemaOptions -> proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
417+ gdeclareNamedSchema :: SchemaOptions -> Proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
410418
411419instance OVERLAPPABLE_ ToSchema a => ToSchema [a] where
412420 declareNamedSchema _ = do
413421 ref <- declareSchemaRef (Proxy :: Proxy a)
414422 return $ unnamed $ mempty
415− & type_ .~ SwaggerArray
423+ & type_ ?~ SwaggerArray
416424 & items ?~ SwaggerItemsObject ref
417425
418426instance OVERLAPPING_ ToSchema String where declareNamedSchema = plain . paramSchemaToSchema
419427instance ToSchema Bool where declareNamedSchema = plain . paramSchemaToSchema
420428instance ToSchema Integer where declareNamedSchema = plain . paramSchemaToSchema
429+instance ToSchema Natural where declareNamedSchema = plain . paramSchemaToSchema
421430instance ToSchema Int where declareNamedSchema = plain . paramSchemaToSchema
422431instance ToSchema Int8 where declareNamedSchema = plain . paramSchemaToSchema
423432instance ToSchema Int16 where declareNamedSchema = plain . paramSchemaToSchema
@@ -437,6 +446,8 @@ instance ToSchema Scientific where declareNamedSchema = plain . paramSchemaToSc
437446instance ToSchema Double where declareNamedSchema = plain . paramSchemaToSchema
438447instance ToSchema Float where declareNamedSchema = plain . paramSchemaToSchema
439448
449+instance HasResolution a => ToSchema (Fixed a) where declareNamedSchema = plain . paramSchemaToSchema
450+
440451instance ToSchema a => ToSchema (Maybe a) where
441452 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)
442453
@@ -459,7 +470,7 @@ instance (ToSchema a, ToSchema b, ToSchema c, ToSchema d, ToSchema e, ToSchema f
459470
460471timeSchema :: T.Text -> Schema
461472timeSchema fmt = mempty
462− & type_ .~ SwaggerString
473+ & type_ ?~ SwaggerString
463474 & format ?~ fmt
464475
465476-- | Format @"date"@ corresponds to @yyyy-mm-dd@ format.
@@ -480,7 +491,7 @@ instance ToSchema ZonedTime where
480491 & example ?~ toJSON (ZonedTime (LocalTime (fromGregorian 2016 7 22) (TimeOfDay 7 40 0)) (hoursToTimeZone 3))
481492
482493instance ToSchema NominalDiffTime where
483− declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy Integer)
494+ declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy Pico)
484495
485496-- |
486497-- >>> toSchema (Proxy :: Proxy UTCTime) ^. format
@@ -492,6 +503,8 @@ instance ToSchema UTCTime where
492503instance ToSchema T.Text where declareNamedSchema = plain . paramSchemaToSchema
493504instance ToSchema TL.Text where declareNamedSchema = plain . paramSchemaToSchema
494505
506+instance ToSchema Version where declareNamedSchema = plain . paramSchemaToSchema
507+
495508#if __GLASGOW_HASKELL__ < 800
496509#else
497510type family ToSchemaByteStringError bs where
@@ -519,8 +532,8 @@ instance (ToJSONKey k, ToSchema k, ToSchema v) => ToSchema (Map k v) where
519532 declareObjectMapSchema = do
520533 schema <- declareSchemaRef (Proxy :: Proxy v)
521534 return $ unnamed $ mempty
522− & type_ .~ SwaggerObject
523− & additionalProperties ?~ schema
535+ & type_ ?~ SwaggerObject
536+ & additionalProperties ?~ AdditionalPropertiesSchema schema
524537
525538instance (ToJSONKey k, ToSchema k, ToSchema v) => ToSchema (HashMap k v) where
526539 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Map k v))
@@ -531,7 +544,7 @@ instance ToSchema a => ToSchema (Map String a) where
531544 declareNamedSchema _ = do
532545 schema <- declareSchemaRef (Proxy :: Proxy a)
533546 return $ unnamed $ mempty
534− & type_ .~ SwaggerObject
547+ & type_ ?~ SwaggerObject
535548 & additionalProperties ?~ schema
536549
537550instance ToSchema a => ToSchema (Map T.Text a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Map String a))
@@ -543,6 +556,12 @@ instance ToSchema a => ToSchema (HashMap TL.Text a) where declareNamedSchema _ =
543556
544557#endif
545558
559+instance OVERLAPPING_ ToSchema Object where
560+ declareNamedSchema _ = pure $ NamedSchema (Just "Object") $ mempty
561+ & type_ ?~ SwaggerObject
562+ & description ?~ "Arbitrary JSON object."
563+ & additionalProperties ?~ AdditionalPropertiesAllowed True
564+
546565instance ToSchema a => ToSchema (V.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
547566instance ToSchema a => ToSchema (VU.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
548567instance ToSchema a => ToSchema (VS.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
@@ -556,6 +575,13 @@ instance ToSchema a => ToSchema (Set a) where
556575
557576instance ToSchema a => ToSchema (HashSet a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Set a))
558577
578+-- | @since 2.2.1
579+instance ToSchema a => ToSchema (NonEmpty a) where
580+ declareNamedSchema _ = do
581+ schema <- declareSchema (Proxy :: Proxy [a])
582+ return $ unnamed $ schema
583+ & minItems .~ Just 1
584+
559585instance ToSchema All where declareNamedSchema = plain . paramSchemaToSchema
560586instance ToSchema Any where declareNamedSchema = plain . paramSchemaToSchema
561587
@@ -565,78 +591,141 @@ instance ToSchema a => ToSchema (First a) where declareNamedSchema _ = unname
565591instance ToSchema a => ToSchema (Last a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
566592instance ToSchema a => ToSchema (Dual a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
567593
594+instance ToSchema a => ToSchema (Identity a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)
595+
568596-- | Default schema for @'Bounded'@, @'Integral'@ types.
569597--
570598-- >>> encode $ toSchemaBoundedIntegral (Proxy :: Proxy Int16)
571599-- "{\"maximum\":32767,\"minimum\":-32768,\"type\":\"integer\"}"
572−toSchemaBoundedIntegral :: forall a proxy. (Bounded a, Integral a) => proxy a -> Schema
600+toSchemaBoundedIntegral :: forall a. (Bounded a, Integral a) => Proxy a -> Schema
573601toSchemaBoundedIntegral _ = mempty
574− & type_ .~ SwaggerInteger
602+ & type_ ?~ SwaggerInteger
575603 & minimum_ ?~ fromInteger (toInteger (minBound :: a))
576604 & maximum_ ?~ fromInteger (toInteger (maxBound :: a))
577605
578606-- | Default generic named schema for @'Bounded'@, @'Integral'@ types.
579−genericToNamedSchemaBoundedIntegral :: forall a d f proxy.
607+genericToNamedSchemaBoundedIntegral :: forall a d f.
580608 ( Bounded a, Integral a
581609 , Generic a, Rep a ~ D1 d f, Datatype d)
582− => SchemaOptions -> proxy a -> NamedSchema
610+ => SchemaOptions -> Proxy a -> NamedSchema
583611genericToNamedSchemaBoundedIntegral opts proxy
584− = NamedSchema (gdatatypeSchemaName opts (Proxy :: Proxy d)) (toSchemaBoundedIntegral proxy)
612+ = genericNameSchema opts proxy (toSchemaBoundedIntegral proxy)
613+
614+-- | Declare a named schema for a @newtype@ wrapper.
615+genericDeclareNamedSchemaNewtype :: forall a d c s i inner.
616+ (Generic a, Datatype d, Rep a ~ D1 d (C1 c (S1 s (K1 i inner))))
617+ => SchemaOptions -- ^ How to derive the name.
618+ -> (Proxy inner -> Declare (Definitions Schema) Schema) -- ^ How to create a schema for the wrapped type.
619+ -> Proxy a
620+ -> Declare (Definitions Schema) NamedSchema
621+genericDeclareNamedSchemaNewtype opts f proxy = genericNameSchema opts proxy <$> f (Proxy :: Proxy inner)
622+
623+-- | Declare 'Schema' for a mapping with 'Bounded' 'Enum' keys.
624+-- This makes a much more useful schema when there aren't many options for key values.
625+--
626+-- >>> data ButtonState = Neutral | Focus | Active | Hover | Disabled deriving (Show, Bounded, Enum, Generic)
627+-- >>> instance ToJSON ButtonState
628+-- >>> instance ToSchema ButtonState
629+-- >>> instance ToJSONKey ButtonState where toJSONKey = toJSONKeyText (T.pack . show)
630+-- >>> type ImageUrl = T.Text
631+-- >>> encode $ toSchemaBoundedEnumKeyMapping (Proxy :: Proxy (Map ButtonState ImageUrl))
632+-- "{\"properties\":{\"Neutral\":{\"type\":\"string\"},\"Focus\":{\"type\":\"string\"},\"Active\":{\"type\":\"string\"},\"Hover\":{\"type\":\"string\"},\"Disabled\":{\"type\":\"string\"}},\"type\":\"object\"}"
633+--
634+-- Note: this is only useful when @key@ is encoded with 'ToJSONKeyText'.
635+-- If it is encoded with 'ToJSONKeyValue' then a regular schema for @[(key, value)]@ is used.
636+declareSchemaBoundedEnumKeyMapping :: forall map key value.
637+ (Bounded key, Enum key, ToJSONKey key, ToSchema key, ToSchema value)
638+ => Proxy (map key value) -> Declare (Definitions Schema) Schema
639+declareSchemaBoundedEnumKeyMapping _ = case toJSONKey :: ToJSONKeyFunction key of
640+ ToJSONKeyText keyToText _ -> objectSchema keyToText
641+ ToJSONKeyValue _ _ -> declareSchema (Proxy :: Proxy [(key, value)])
642+ where
643+ objectSchema keyToText = do
644+ valueRef <- declareSchemaRef (Proxy :: Proxy value)
645+ let allKeys = [minBound..maxBound :: key]
646+ mkPair k = (keyToText k, valueRef)
647+ return $ mempty
648+ & type_ ?~ SwaggerObject
649+ & properties .~ InsOrdHashMap.fromList (map mkPair allKeys)
650+
651+-- | A 'Schema' for a mapping with 'Bounded' 'Enum' keys.
652+-- This makes a much more useful schema when there aren't many options for key values.
653+--
654+-- >>> data ButtonState = Neutral | Focus | Active | Hover | Disabled deriving (Show, Bounded, Enum, Generic)
655+-- >>> instance ToJSON ButtonState
656+-- >>> instance ToSchema ButtonState
657+-- >>> instance ToJSONKey ButtonState where toJSONKey = toJSONKeyText (T.pack . show)
658+-- >>> type ImageUrl = T.Text
659+-- >>> encode $ toSchemaBoundedEnumKeyMapping (Proxy :: Proxy (Map ButtonState ImageUrl))
660+-- "{\"properties\":{\"Neutral\":{\"type\":\"string\"},\"Focus\":{\"type\":\"string\"},\"Active\":{\"type\":\"string\"},\"Hover\":{\"type\":\"string\"},\"Disabled\":{\"type\":\"string\"}},\"type\":\"object\"}"
661+--
662+-- Note: this is only useful when @key@ is encoded with 'ToJSONKeyText'.
663+-- If it is encoded with 'ToJSONKeyValue' then a regular schema for @[(key, value)]@ is used.
664+toSchemaBoundedEnumKeyMapping :: forall map key value.
665+ (Bounded key, Enum key, ToJSONKey key, ToSchema key, ToSchema value)
666+ => Proxy (map key value) -> Schema
667+toSchemaBoundedEnumKeyMapping = flip evalDeclare mempty . declareSchemaBoundedEnumKeyMapping
585668
586669-- | A configurable generic @'Schema'@ creator.
587670genericDeclareSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareSchemaUnrestricted") =>
588− SchemaOptions -> proxy a -> Declare (Definitions Schema) Schema
671+ SchemaOptions -> Proxy a -> Declare (Definitions Schema) Schema
589672genericDeclareSchema = genericDeclareSchemaUnrestricted
590673
591674-- | A configurable generic @'NamedSchema'@ creator.
592675-- This function applied to @'defaultSchemaOptions'@
593676-- is used as the default for @'declareNamedSchema'@
594677-- when the type is an instance of @'Generic'@.
595−genericDeclareNamedSchema :: forall a proxy. (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareNamedSchemaUnrestricted") =>
596− SchemaOptions -> proxy a -> Declare (Definitions Schema) NamedSchema
678+genericDeclareNamedSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareNamedSchemaUnrestricted") =>
679+ SchemaOptions -> Proxy a -> Declare (Definitions Schema) NamedSchema
597680genericDeclareNamedSchema = genericDeclareNamedSchemaUnrestricted
598681
599682-- | A configurable generic @'Schema'@ creator.
600683--
601684-- Unlike 'genericDeclareSchema' also works for mixed sum types.
602685-- Use with care since some Swagger tools do not support well schemas for mixed sum types.
603−genericDeclareSchemaUnrestricted :: (Generic a, GToSchema (Rep a)) => SchemaOptions -> proxy a -> Declare (Definitions Schema) Schema
686+genericDeclareSchemaUnrestricted :: (Generic a, GToSchema (Rep a)) => SchemaOptions -> Proxy a -> Declare (Definitions Schema) Schema
604687genericDeclareSchemaUnrestricted opts proxy = _namedSchemaSchema <$> genericDeclareNamedSchemaUnrestricted opts proxy
605688
606689-- | A configurable generic @'NamedSchema'@ creator.
607690--
608691-- Unlike 'genericDeclareNamedSchema' also works for mixed sum types.
609692-- Use with care since some Swagger tools do not support well schemas for mixed sum types.
610−genericDeclareNamedSchemaUnrestricted :: forall a proxy. (Generic a, GToSchema (Rep a)) =>
611− SchemaOptions -> proxy a -> Declare (Definitions Schema) NamedSchema
693+genericDeclareNamedSchemaUnrestricted :: forall a. (Generic a, GToSchema (Rep a)) =>
694+ SchemaOptions -> Proxy a -> Declare (Definitions Schema) NamedSchema
612695genericDeclareNamedSchemaUnrestricted opts _ = gdeclareNamedSchema opts (Proxy :: Proxy (Rep a)) mempty
613696
614−gdatatypeSchemaName :: forall proxy d. Datatype d => SchemaOptions -> proxy d -> Maybe T.Text
615−gdatatypeSchemaName opts _ = case name of
697+-- | Derive a 'Generic'-based name for a datatype and assign it to a given 'Schema'.
698+genericNameSchema :: forall a d f.
699+ (Generic a, Rep a ~ D1 d f, Datatype d)
700+ => SchemaOptions -> Proxy a -> Schema -> NamedSchema
701+genericNameSchema opts _ = NamedSchema (gdatatypeSchemaName opts (Proxy :: Proxy d))
702+
703+gdatatypeSchemaName :: forall d. Datatype d => SchemaOptions -> Proxy d -> Maybe T.Text
704+gdatatypeSchemaName opts _ = case orig of
616705 (c:_) | isAlpha c && isUpper c -> Just (T.pack name)
617706 _ -> Nothing
618707 where
619− name = datatypeNameModifier opts (datatypeName (Proxy3 :: Proxy3 d f a))
708+ orig = datatypeName (Proxy3 :: Proxy3 d f a)
709+ name = datatypeNameModifier opts orig
620710
621711-- | Lift a plain @'ParamSchema'@ into a model @'NamedSchema'@.
622−paramSchemaToNamedSchema :: forall a d f proxy.
623− (ToParamSchema a, Generic a, Rep a ~ D1 d f, Datatype d)
624− => SchemaOptions -> proxy a -> NamedSchema
625−paramSchemaToNamedSchema opts proxy = NamedSchema (gdatatypeSchemaName opts (Proxy :: Proxy d)) (paramSchemaToSchema proxy)
712+paramSchemaToNamedSchema :: (ToParamSchema a, Generic a, Rep a ~ D1 d f, Datatype d) =>
713+ SchemaOptions -> Proxy a -> NamedSchema
714+paramSchemaToNamedSchema opts proxy = genericNameSchema opts proxy (paramSchemaToSchema proxy)
626715
627716-- | Lift a plain @'ParamSchema'@ into a model @'Schema'@.
628−paramSchemaToSchema :: forall a proxy. ToParamSchema a => proxy a -> Schema
629−paramSchemaToSchema _ = mempty & paramSchema .~ toParamSchema (Proxy :: Proxy a)
717+paramSchemaToSchema :: ToParamSchema a => Proxy a -> Schema
718+paramSchemaToSchema proxy = mempty & paramSchema .~ toParamSchema proxy
630719
631720nullarySchema :: Schema
632721nullarySchema = mempty
633− & type_ .~ SwaggerArray
722+ & type_ ?~ SwaggerArray
634723 & items ?~ SwaggerItemsArray []
635724
636−gtoNamedSchema :: GToSchema f => SchemaOptions -> proxy f -> NamedSchema
725+gtoNamedSchema :: GToSchema f => SchemaOptions -> Proxy f -> NamedSchema
637726gtoNamedSchema opts proxy = undeclare $ gdeclareNamedSchema opts proxy mempty
638727
639−gdeclareSchema :: GToSchema f => SchemaOptions -> proxy f -> Declare (Definitions Schema) Schema
728+gdeclareSchema :: GToSchema f => SchemaOptions -> Proxy f -> Declare (Definitions Schema) Schema
640729gdeclareSchema opts proxy = _namedSchemaSchema <$> gdeclareNamedSchema opts proxy mempty
641730
642731instance (GToSchema f, GToSchema g) => GToSchema (f :*: g) where
@@ -656,7 +745,7 @@ instance OVERLAPPING_ Constructor c => GToSchema (C1 c U1) where
656745 gdeclareNamedSchema = gdeclareNamedSumSchema
657746
658747-- | Single field constructor.
659−instance (Selector s, GToSchema f) => GToSchema (C1 c (S1 s f)) where
748+instance (Selector s, GToSchema f, GToSchema (S1 s f)) => GToSchema (C1 c (S1 s f)) where
660749 gdeclareNamedSchema opts _ s
661750 | unwrapUnaryRecords opts = fieldSchema
662751 | otherwise =
@@ -670,7 +759,7 @@ instance (Selector s, GToSchema f) => GToSchema (C1 c (S1 s f)) where
670759 recordSchema = gdeclareNamedSchema opts (Proxy :: Proxy (S1 s f)) s
671760 fieldSchema = gdeclareNamedSchema opts (Proxy :: Proxy f) s
672761
673−gdeclareSchemaRef :: GToSchema a => SchemaOptions -> proxy a -> Declare (Definitions Schema) (Referenced Schema)
762+gdeclareSchemaRef :: GToSchema a => SchemaOptions -> Proxy a -> Declare (Definitions Schema) (Referenced Schema)
674763gdeclareSchemaRef opts proxy = do
675764 case gtoNamedSchema opts proxy of
676765 NamedSchema (Just name) schema -> do
@@ -701,12 +790,12 @@ withFieldSchema opts _ isRequiredField schema = do
701790 return $
702791 if T.null fname
703792 then schema
704− & type_ .~ SwaggerArray
793+ & type_ ?~ SwaggerArray
705794 & items %~ appendItem ref
706795 & maxItems %~ Just . maybe 1 (+1) -- increment maxItems
707796 & minItems %~ Just . maybe 1 (+1) -- increment minItems
708797 else schema
709− & type_ .~ SwaggerObject
798+ & type_ ?~ SwaggerObject
710799 & properties . at fname ?~ ref
711800 & if isRequiredField
712801 then required %~ (++ [fname])
@@ -734,7 +823,7 @@ instance ( GSumToSchema f
734823 where
735824 gdeclareNamedSchema = gdeclareNamedSumSchema
736825
737−gdeclareNamedSumSchema :: GSumToSchema f => SchemaOptions -> proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
826+gdeclareNamedSumSchema :: GSumToSchema f => SchemaOptions -> Proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
738827gdeclareNamedSumSchema opts proxy s
739828 | allNullaryToStringTag opts && allNullary = pure $ unnamed (toStringTag sumSchema)
740829 | otherwise = (unnamed . fst) <$> runWriterT declareSumSchema
@@ -743,29 +832,29 @@ gdeclareNamedSumSchema opts proxy s
743832 (sumSchema, All allNullary) = undeclare (runWriterT declareSumSchema)
744833
745834 toStringTag schema = mempty
746− & type_ .~ SwaggerString
835+ & type_ ?~ SwaggerString
747836 & enum_ ?~ map toJSON (schema ^.. properties.ifolded.asIndex)
748837
749838type AllNullary = All
750839
751840class GSumToSchema (f :: * -> *) where
752− gsumToSchema :: SchemaOptions -> proxy f -> Schema -> WriterT AllNullary (Declare (Definitions Schema)) Schema
841+ gsumToSchema :: SchemaOptions -> Proxy f -> Schema -> WriterT AllNullary (Declare (Definitions Schema)) Schema
753842
754843instance (GSumToSchema f, GSumToSchema g) => GSumToSchema (f :+: g) where
755844 gsumToSchema opts _ = gsumToSchema opts (Proxy :: Proxy f) >=> gsumToSchema opts (Proxy :: Proxy g)
756845
757−gsumConToSchemaWith :: forall c f proxy. (GToSchema (C1 c f), Constructor c) =>
758− Referenced Schema -> SchemaOptions -> proxy (C1 c f) -> Schema -> Schema
846+gsumConToSchemaWith :: forall c f. (GToSchema (C1 c f), Constructor c) =>
847+ Referenced Schema -> SchemaOptions -> Proxy (C1 c f) -> Schema -> Schema
759848gsumConToSchemaWith ref opts _ schema = schema
760− & type_ .~ SwaggerObject
849+ & type_ ?~ SwaggerObject
761850 & properties . at tag ?~ ref
762851 & maxProperties ?~ 1
763852 & minProperties ?~ 1
764853 where
765854 tag = T.pack (constructorTagModifier opts (conName (Proxy3 :: Proxy3 c f p)))
766855
767−gsumConToSchema :: forall c f proxy. (GToSchema (C1 c f), Constructor c) =>
768− SchemaOptions -> proxy (C1 c f) -> Schema -> Declare (Definitions Schema) Schema
856+gsumConToSchema :: (GToSchema (C1 c f), Constructor c) =>
857+ SchemaOptions -> Proxy (C1 c f) -> Schema -> Declare (Definitions Schema) Schema
769858gsumConToSchema opts proxy schema = do
770859 ref <- gdeclareSchemaRef opts proxy
771860 return $ gsumConToSchemaWith ref opts proxy schema
@@ -789,3 +878,5 @@ data Proxy3 a b c = Proxy3
789878
790879-- $setup
791880-- >>> import Data.Swagger
881+-- >>> import Data.Aeson (encode)
882+-- >>> import Data.Aeson.Types (toJSONKeyText)