@@ -32,7 +32,7 @@ import Data.Data.Lens (template)
33import Control.Monad
33import Control.Monad
34import Control.Monad.Writer
34import Control.Monad.Writer
35−import Data.Aeson
35+import Data.Aeson (ToJSON (..), ToJSONKey (..), ToJSONKeyFunction (..), Value (..), Object(..))
36import Data.Char
36import Data.Char
37import Data.Data (Data)
37import Data.Data (Data)
38import Data.Foldable (traverse_)
38import Data.Foldable (traverse_)
@@ -44,9 +44,11 @@ import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
44import Data.Int
44import Data.Int
45import Data.IntSet (IntSet)
45import Data.IntSet (IntSet)
46import Data.IntMap (IntMap)
46import Data.IntMap (IntMap)
47+import Data.List.NonEmpty.Compat (NonEmpty)
47import Data.Map (Map)
48import Data.Map (Map)
48import Data.Proxy
49import Data.Proxy
49import Data.Scientific (Scientific)
50import Data.Scientific (Scientific)
51+import Data.Fixed (Fixed, HasResolution, Pico)
50import Data.Set (Set)
52import Data.Set (Set)
51import qualified Data.Text as T
53import qualified Data.Text as T
52import qualified Data.Text.Lazy as TL
54import qualified Data.Text.Lazy as TL
@@ -55,6 +57,8 @@ import qualified Data.Vector as V
55import qualified Data.Vector.Primitive as VP
57import qualified Data.Vector.Primitive as VP
56import qualified Data.Vector.Storable as VS
58import qualified Data.Vector.Storable as VS
57import qualified Data.Vector.Unboxed as VU
59import qualified Data.Vector.Unboxed as VU
60+import Data.Version (Version)
61+import Numeric.Natural.Compat (Natural)
58import Data.Word
62import Data.Word
59import GHC.Generics
63import GHC.Generics
60import qualified Data.UUID.Types as UUID
64import qualified Data.UUID.Types as UUID
@@ -107,7 +111,7 @@ rename name (NamedSchema _ schema) = NamedSchema name schema
107-- declareNamedSchema _ = do
111-- declareNamedSchema _ = do
108-- doubleSchema <- declareSchemaRef (Proxy :: Proxy Double)
112-- doubleSchema <- declareSchemaRef (Proxy :: Proxy Double)
109-- return $ NamedSchema (Just \"Coord\") $ mempty
113-- return $ NamedSchema (Just \"Coord\") $ mempty
110−-- & type_ .~ SwaggerObject
114+-- & type_ ?~ SwaggerObject
111-- & properties .~
115-- & properties .~
112-- [ (\"x\", doubleSchema)
116-- [ (\"x\", doubleSchema)
113-- , (\"y\", doubleSchema)
117-- , (\"y\", doubleSchema)
@@ -138,13 +142,17 @@ class ToSchema a where
138 -- together with all used definitions.
142 -- together with all used definitions.
139 -- Note that the schema itself is included in definitions
143 -- Note that the schema itself is included in definitions
140 -- only if it is recursive (and thus needs its definition in scope).
144 -- 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
142 default declareNamedSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareNamedSchemaUnrestricted") =>
146 default declareNamedSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareNamedSchemaUnrestricted") =>
143− proxy a -> Declare (Definitions Schema) NamedSchema
147+ Proxy a -> Declare (Definitions Schema) NamedSchema
144 declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
148 declareNamedSchema = genericDeclareNamedSchema defaultSchemaOptions
150+instance ToSchema TimeOfDay where
151+ declareNamedSchema _ = pure $ named "TimeOfDay" $ timeSchema "hh:MM:ss"
152+ & example ?~ toJSON (TimeOfDay 12 33 15)
146-- | Convert a type into a schema and declare all used schema definitions.
154-- | 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
148declareSchema = fmap _namedSchemaSchema . declareNamedSchema
156declareSchema = fmap _namedSchemaSchema . declareNamedSchema
150-- | Convert a type into an optionally named schema.
158-- | Convert a type into an optionally named schema.
@@ -158,7 +166,7 @@ declareSchema = fmap _namedSchemaSchema . declareNamedSchema
158-- Just "Day"
166-- Just "Day"
159-- >>> encode (toNamedSchema (Proxy :: Proxy Day) ^. schema)
167-- >>> encode (toNamedSchema (Proxy :: Proxy Day) ^. schema)
160-- "{\"example\":\"2016-07-22\",\"format\":\"date\",\"type\":\"string\"}"
168-- "{\"example\":\"2016-07-22\",\"format\":\"date\",\"type\":\"string\"}"
161−toNamedSchema :: ToSchema a => proxy a -> NamedSchema
169+toNamedSchema :: ToSchema a => Proxy a -> NamedSchema
162toNamedSchema = undeclare . declareNamedSchema
170toNamedSchema = undeclare . declareNamedSchema
164-- | Get type's schema name according to its @'ToSchema'@ instance.
172-- | Get type's schema name according to its @'ToSchema'@ instance.
@@ -168,7 +176,7 @@ toNamedSchema = undeclare . declareNamedSchema
169-- >>> schemaName (Proxy :: Proxy UTCTime)
177-- >>> schemaName (Proxy :: Proxy UTCTime)
170-- Just "UTCTime"
178-- Just "UTCTime"
171−schemaName :: ToSchema a => proxy a -> Maybe T.Text
179+schemaName :: ToSchema a => Proxy a -> Maybe T.Text
172schemaName = _namedSchemaName . toNamedSchema
180schemaName = _namedSchemaName . toNamedSchema
174-- | Convert a type into a schema.
182-- | Convert a type into a schema.
@@ -178,7 +186,7 @@ schemaName = _namedSchemaName . toNamedSchema
179-- >>> encode $ toSchema (Proxy :: Proxy [Day])
187-- >>> encode $ toSchema (Proxy :: Proxy [Day])
180-- "{\"items\":{\"$ref\":\"#/definitions/Day\"},\"type\":\"array\"}"
188-- "{\"items\":{\"$ref\":\"#/definitions/Day\"},\"type\":\"array\"}"
181−toSchema :: ToSchema a => proxy a -> Schema
189+toSchema :: ToSchema a => Proxy a -> Schema
182toSchema = _namedSchemaSchema . toNamedSchema
190toSchema = _namedSchemaSchema . toNamedSchema
184-- | Convert a type into a referenced schema if possible.
192-- | Convert a type into a referenced schema if possible.
@@ -189,7 +197,7 @@ toSchema = _namedSchemaSchema . toNamedSchema
190-- >>> encode $ toSchemaRef (Proxy :: Proxy Day)
198-- >>> encode $ toSchemaRef (Proxy :: Proxy Day)
191-- "{\"$ref\":\"#/definitions/Day\"}"
199-- "{\"$ref\":\"#/definitions/Day\"}"
192−toSchemaRef :: ToSchema a => proxy a -> Referenced Schema
200+toSchemaRef :: ToSchema a => Proxy a -> Referenced Schema
193toSchemaRef = undeclare . declareSchemaRef
201toSchemaRef = undeclare . declareSchemaRef
195-- | Convert a type into a referenced schema if possible
203-- | Convert a type into a referenced schema if possible
@@ -199,7 +207,7 @@ toSchemaRef = undeclare . declareSchemaRef
199-- Schema definitions are typically declared for every referenced schema.
207-- Schema definitions are typically declared for every referenced schema.
200-- If @'declareSchemaRef'@ returns a reference, a corresponding schema
208-- If @'declareSchemaRef'@ returns a reference, a corresponding schema
201-- will be declared (regardless of whether it is recusive or not).
209-- 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)
203declareSchemaRef proxy = do
211declareSchemaRef proxy = do
204 case toNamedSchema proxy of
212 case toNamedSchema proxy of
205 NamedSchema (Just name) schema -> do
213 NamedSchema (Just name) schema -> do
@@ -261,7 +269,7 @@ inlineAllSchemas = inlineSchemasWhen (const True)
262-- __WARNING:__ @'toInlinedSchema'@ will produce infinite schema
270-- __WARNING:__ @'toInlinedSchema'@ will produce infinite schema
263-- when inlining recursive schemas.
271-- when inlining recursive schemas.
264−toInlinedSchema :: ToSchema a => proxy a -> Schema
272+toInlinedSchema :: ToSchema a => Proxy a -> Schema
265toInlinedSchema proxy = inlineAllSchemas defs schema
273toInlinedSchema proxy = inlineAllSchemas defs schema
267 (defs, schema) = runDeclare (declareSchema proxy) mempty
275 (defs, schema) = runDeclare (declareSchema proxy) mempty
@@ -290,20 +298,20 @@ inlineNonRecursiveSchemas defs = inlineSchemasWhen nonRecursive defs
290-- | Default schema for binary data (any sequence of octets).
298-- | Default schema for binary data (any sequence of octets).
291binarySchema :: Schema
299binarySchema :: Schema
292binarySchema = mempty
300binarySchema = mempty
293− & type_ .~ SwaggerString
301+ & type_ ?~ SwaggerString
294 & format ?~ "binary"
302 & format ?~ "binary"
296-- | Default schema for binary data (base64 encoded).
304-- | Default schema for binary data (base64 encoded).
297byteSchema :: Schema
305byteSchema :: Schema
298byteSchema = mempty
306byteSchema = mempty
299− & type_ .~ SwaggerString
307+ & type_ ?~ SwaggerString
300 & format ?~ "byte"
308 & format ?~ "byte"
302-- | Default schema for password string.
310-- | Default schema for password string.
303-- @"password"@ format is used to hint UIs the input needs to be obscured.
311-- @"password"@ format is used to hint UIs the input needs to be obscured.
304passwordSchema :: Schema
312passwordSchema :: Schema
305passwordSchema = mempty
313passwordSchema = mempty
306− & type_ .~ SwaggerString
314+ & type_ ?~ SwaggerString
307 & format ?~ "password"
315 & format ?~ "password"
309-- | Make an unrestrictive sketch of a @'Schema'@ based on a @'ToJSON'@ instance.
317-- | Make an unrestrictive sketch of a @'Schema'@ based on a @'ToJSON'@ instance.
@@ -329,12 +337,12 @@ sketchSchema = sketch . toJSON
329 sketch js@(Bool _) = go js
337 sketch js@(Bool _) = go js
330 sketch js = go js & example ?~ js
338 sketch js = go js & example ?~ js
332− go Null = mempty & type_ .~ SwaggerNull
340+ go Null = mempty & type_ ?~ SwaggerNull
333− go (Bool _) = mempty & type_ .~ SwaggerBoolean
341+ go (Bool _) = mempty & type_ ?~ SwaggerBoolean
334− go (String _) = mempty & type_ .~ SwaggerString
342+ go (String _) = mempty & type_ ?~ SwaggerString
335− go (Number _) = mempty & type_ .~ SwaggerNumber
343+ go (Number _) = mempty & type_ ?~ SwaggerNumber
336 go (Array xs) = mempty
344 go (Array xs) = mempty
337− & type_ .~ SwaggerArray
345+ & type_ ?~ SwaggerArray
338 & items ?~ case ischema of
346 & items ?~ case ischema of
339 Just s -> SwaggerItemsObject (Inline s)
347 Just s -> SwaggerItemsObject (Inline s)
340 _ -> SwaggerItemsArray (map Inline ys)
348 _ -> SwaggerItemsArray (map Inline ys)
@@ -346,7 +354,7 @@ sketchSchema = sketch . toJSON
346 (z:_) | allSame -> Just z
354 (z:_) | allSame -> Just z
347 _ -> Nothing
355 _ -> Nothing
348 go (Object o) = mempty
356 go (Object o) = mempty
349− & type_ .~ SwaggerObject
357+ & type_ ?~ SwaggerObject
350 & required .~ HashMap.keys o
358 & required .~ HashMap.keys o
351 & properties .~ fmap (Inline . go) (InsOrdHashMap.fromHashMap o)
359 & properties .~ fmap (Inline . go) (InsOrdHashMap.fromHashMap o)
@@ -369,24 +377,24 @@ sketchSchema = sketch . toJSON
369sketchStrictSchema :: ToJSON a => a -> Schema
377sketchStrictSchema :: ToJSON a => a -> Schema
370sketchStrictSchema = go . toJSON
378sketchStrictSchema = go . toJSON
372− go Null = mempty & type_ .~ SwaggerNull
380+ go Null = mempty & type_ ?~ SwaggerNull
373 go js@(Bool _) = mempty
381 go js@(Bool _) = mempty
374− & type_ .~ SwaggerBoolean
382+ & type_ ?~ SwaggerBoolean
375 & enum_ ?~ [js]
383 & enum_ ?~ [js]
376 go js@(String s) = mempty
384 go js@(String s) = mempty
377− & type_ .~ SwaggerString
385+ & type_ ?~ SwaggerString
378 & maxLength ?~ fromIntegral (T.length s)
386 & maxLength ?~ fromIntegral (T.length s)
379 & minLength ?~ fromIntegral (T.length s)
387 & minLength ?~ fromIntegral (T.length s)
380 & pattern ?~ s
388 & pattern ?~ s
381 & enum_ ?~ [js]
389 & enum_ ?~ [js]
382 go js@(Number n) = mempty
390 go js@(Number n) = mempty
383− & type_ .~ SwaggerNumber
391+ & type_ ?~ SwaggerNumber
384 & maximum_ ?~ n
392 & maximum_ ?~ n
385 & minimum_ ?~ n
393 & minimum_ ?~ n
386 & multipleOf ?~ n
394 & multipleOf ?~ n
387 & enum_ ?~ [js]
395 & enum_ ?~ [js]
388 go js@(Array xs) = mempty
396 go js@(Array xs) = mempty
389− & type_ .~ SwaggerArray
397+ & type_ ?~ SwaggerArray
390 & maxItems ?~ fromIntegral sz
398 & maxItems ?~ fromIntegral sz
391 & minItems ?~ fromIntegral sz
399 & minItems ?~ fromIntegral sz
392 & items ?~ SwaggerItemsArray (map (Inline . go) (V.toList xs))
400 & items ?~ SwaggerItemsArray (map (Inline . go) (V.toList xs))
@@ -396,7 +404,7 @@ sketchStrictSchema = go . toJSON
396 sz = length xs
404 sz = length xs
397 allUnique = sz == HashSet.size (HashSet.fromList (V.toList xs))
405 allUnique = sz == HashSet.size (HashSet.fromList (V.toList xs))
398 go js@(Object o) = mempty
406 go js@(Object o) = mempty
399− & type_ .~ SwaggerObject
407+ & type_ ?~ SwaggerObject
400 & required .~ names
408 & required .~ names
401 & properties .~ fmap (Inline . go) (InsOrdHashMap.fromHashMap o)
409 & properties .~ fmap (Inline . go) (InsOrdHashMap.fromHashMap o)
402 & maxProperties ?~ fromIntegral (length names)
410 & maxProperties ?~ fromIntegral (length names)
@@ -406,18 +414,19 @@ sketchStrictSchema = go . toJSON
406 names = HashMap.keys o
414 names = HashMap.keys o
408class GToSchema (f :: * -> *) where
416class GToSchema (f :: * -> *) where
409− gdeclareNamedSchema :: SchemaOptions -> proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
417+ gdeclareNamedSchema :: SchemaOptions -> Proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
411instance OVERLAPPABLE_ ToSchema a => ToSchema [a] where
419instance OVERLAPPABLE_ ToSchema a => ToSchema [a] where
412 declareNamedSchema _ = do
420 declareNamedSchema _ = do
413 ref <- declareSchemaRef (Proxy :: Proxy a)
421 ref <- declareSchemaRef (Proxy :: Proxy a)
414 return $ unnamed $ mempty
422 return $ unnamed $ mempty
415− & type_ .~ SwaggerArray
423+ & type_ ?~ SwaggerArray
416 & items ?~ SwaggerItemsObject ref
424 & items ?~ SwaggerItemsObject ref
418instance OVERLAPPING_ ToSchema String where declareNamedSchema = plain . paramSchemaToSchema
426instance OVERLAPPING_ ToSchema String where declareNamedSchema = plain . paramSchemaToSchema
419instance ToSchema Bool where declareNamedSchema = plain . paramSchemaToSchema
427instance ToSchema Bool where declareNamedSchema = plain . paramSchemaToSchema
420instance ToSchema Integer where declareNamedSchema = plain . paramSchemaToSchema
428instance ToSchema Integer where declareNamedSchema = plain . paramSchemaToSchema
429+instance ToSchema Natural where declareNamedSchema = plain . paramSchemaToSchema
421instance ToSchema Int where declareNamedSchema = plain . paramSchemaToSchema
430instance ToSchema Int where declareNamedSchema = plain . paramSchemaToSchema
422instance ToSchema Int8 where declareNamedSchema = plain . paramSchemaToSchema
431instance ToSchema Int8 where declareNamedSchema = plain . paramSchemaToSchema
423instance ToSchema Int16 where declareNamedSchema = plain . paramSchemaToSchema
432instance ToSchema Int16 where declareNamedSchema = plain . paramSchemaToSchema
@@ -437,6 +446,8 @@ instance ToSchema Scientific where declareNamedSchema = plain . paramSchemaToSc
437instance ToSchema Double where declareNamedSchema = plain . paramSchemaToSchema
446instance ToSchema Double where declareNamedSchema = plain . paramSchemaToSchema
438instance ToSchema Float where declareNamedSchema = plain . paramSchemaToSchema
447instance ToSchema Float where declareNamedSchema = plain . paramSchemaToSchema
449+instance HasResolution a => ToSchema (Fixed a) where declareNamedSchema = plain . paramSchemaToSchema
440instance ToSchema a => ToSchema (Maybe a) where
451instance ToSchema a => ToSchema (Maybe a) where
441 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)
452 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)
@@ -459,7 +470,7 @@ instance (ToSchema a, ToSchema b, ToSchema c, ToSchema d, ToSchema e, ToSchema f
460timeSchema :: T.Text -> Schema
471timeSchema :: T.Text -> Schema
461timeSchema fmt = mempty
472timeSchema fmt = mempty
462− & type_ .~ SwaggerString
473+ & type_ ?~ SwaggerString
463 & format ?~ fmt
474 & format ?~ fmt
465-- | Format @"date"@ corresponds to @yyyy-mm-dd@ format.
476-- | Format @"date"@ corresponds to @yyyy-mm-dd@ format.
@@ -480,7 +491,7 @@ instance ToSchema ZonedTime where
480 & example ?~ toJSON (ZonedTime (LocalTime (fromGregorian 2016 7 22) (TimeOfDay 7 40 0)) (hoursToTimeZone 3))
491 & example ?~ toJSON (ZonedTime (LocalTime (fromGregorian 2016 7 22) (TimeOfDay 7 40 0)) (hoursToTimeZone 3))
482instance ToSchema NominalDiffTime where
493instance ToSchema NominalDiffTime where
483− declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy Integer)
494+ declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy Pico)
486-- >>> toSchema (Proxy :: Proxy UTCTime) ^. format
497-- >>> toSchema (Proxy :: Proxy UTCTime) ^. format
@@ -492,6 +503,8 @@ instance ToSchema UTCTime where
492instance ToSchema T.Text where declareNamedSchema = plain . paramSchemaToSchema
503instance ToSchema T.Text where declareNamedSchema = plain . paramSchemaToSchema
493instance ToSchema TL.Text where declareNamedSchema = plain . paramSchemaToSchema
504instance ToSchema TL.Text where declareNamedSchema = plain . paramSchemaToSchema
506+instance ToSchema Version where declareNamedSchema = plain . paramSchemaToSchema
495#if __GLASGOW_HASKELL__ < 800
508#if __GLASGOW_HASKELL__ < 800
497type family ToSchemaByteStringError bs where
510type family ToSchemaByteStringError bs where
@@ -519,8 +532,8 @@ instance (ToJSONKey k, ToSchema k, ToSchema v) => ToSchema (Map k v) where
519 declareObjectMapSchema = do
532 declareObjectMapSchema = do
520 schema <- declareSchemaRef (Proxy :: Proxy v)
533 schema <- declareSchemaRef (Proxy :: Proxy v)
521 return $ unnamed $ mempty
534 return $ unnamed $ mempty
522− & type_ .~ SwaggerObject
535+ & type_ ?~ SwaggerObject
523− & additionalProperties ?~ schema
536+ & additionalProperties ?~ AdditionalPropertiesSchema schema
525instance (ToJSONKey k, ToSchema k, ToSchema v) => ToSchema (HashMap k v) where
538instance (ToJSONKey k, ToSchema k, ToSchema v) => ToSchema (HashMap k v) where
526 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Map k v))
539 declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Map k v))
@@ -531,7 +544,7 @@ instance ToSchema a => ToSchema (Map String a) where
531 declareNamedSchema _ = do
544 declareNamedSchema _ = do
532 schema <- declareSchemaRef (Proxy :: Proxy a)
545 schema <- declareSchemaRef (Proxy :: Proxy a)
533 return $ unnamed $ mempty
546 return $ unnamed $ mempty
534− & type_ .~ SwaggerObject
547+ & type_ ?~ SwaggerObject
535 & additionalProperties ?~ schema
548 & additionalProperties ?~ schema
537instance ToSchema a => ToSchema (Map T.Text a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Map String a))
550instance 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 _ =
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
546instance ToSchema a => ToSchema (V.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
565instance ToSchema a => ToSchema (V.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
547instance ToSchema a => ToSchema (VU.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
566instance ToSchema a => ToSchema (VU.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
548instance ToSchema a => ToSchema (VS.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
567instance ToSchema a => ToSchema (VS.Vector a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy [a])
@@ -556,6 +575,13 @@ instance ToSchema a => ToSchema (Set a) where
557instance ToSchema a => ToSchema (HashSet a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Set a))
576instance ToSchema a => ToSchema (HashSet a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy (Set a))
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
559instance ToSchema All where declareNamedSchema = plain . paramSchemaToSchema
585instance ToSchema All where declareNamedSchema = plain . paramSchemaToSchema
560instance ToSchema Any where declareNamedSchema = plain . paramSchemaToSchema
586instance ToSchema Any where declareNamedSchema = plain . paramSchemaToSchema
@@ -565,78 +591,141 @@ instance ToSchema a => ToSchema (First a) where declareNamedSchema _ = unname
565instance ToSchema a => ToSchema (Last a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
591instance ToSchema a => ToSchema (Last a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
566instance ToSchema a => ToSchema (Dual a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
592instance ToSchema a => ToSchema (Dual a) where declareNamedSchema _ = unname <$> declareNamedSchema (Proxy :: Proxy a)
594+instance ToSchema a => ToSchema (Identity a) where declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)
568-- | Default schema for @'Bounded'@, @'Integral'@ types.
596-- | Default schema for @'Bounded'@, @'Integral'@ types.
570-- >>> encode $ toSchemaBoundedIntegral (Proxy :: Proxy Int16)
598-- >>> encode $ toSchemaBoundedIntegral (Proxy :: Proxy Int16)
571-- "{\"maximum\":32767,\"minimum\":-32768,\"type\":\"integer\"}"
599-- "{\"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
573toSchemaBoundedIntegral _ = mempty
601toSchemaBoundedIntegral _ = mempty
574− & type_ .~ SwaggerInteger
602+ & type_ ?~ SwaggerInteger
575 & minimum_ ?~ fromInteger (toInteger (minBound :: a))
603 & minimum_ ?~ fromInteger (toInteger (minBound :: a))
576 & maximum_ ?~ fromInteger (toInteger (maxBound :: a))
604 & maximum_ ?~ fromInteger (toInteger (maxBound :: a))
578-- | Default generic named schema for @'Bounded'@, @'Integral'@ types.
606-- | Default generic named schema for @'Bounded'@, @'Integral'@ types.
579−genericToNamedSchemaBoundedIntegral :: forall a d f proxy.
607+genericToNamedSchemaBoundedIntegral :: forall a d f.
580 ( Bounded a, Integral a
608 ( Bounded a, Integral a
581 , Generic a, Rep a ~ D1 d f, Datatype d)
609 , Generic a, Rep a ~ D1 d f, Datatype d)
582− => SchemaOptions -> proxy a -> NamedSchema
610+ => SchemaOptions -> Proxy a -> NamedSchema
583genericToNamedSchemaBoundedIntegral opts proxy
611genericToNamedSchemaBoundedIntegral opts proxy
584− = NamedSchema (gdatatypeSchemaName opts (Proxy :: Proxy d)) (toSchemaBoundedIntegral proxy)
612+ = genericNameSchema opts proxy (toSchemaBoundedIntegral proxy)
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.
620+ -> Declare (Definitions Schema) NamedSchema
621+genericDeclareNamedSchemaNewtype opts f proxy = genericNameSchema opts proxy <$> f (Proxy :: Proxy inner)
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.
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\"}"
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)])
643+ objectSchema keyToText = do
644+ valueRef <- declareSchemaRef (Proxy :: Proxy value)
645+ let allKeys = [minBound..maxBound :: key]
646+ mkPair k = (keyToText k, valueRef)
648+ & type_ ?~ SwaggerObject
649+ & properties .~ InsOrdHashMap.fromList (map mkPair allKeys)
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.
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\"}"
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
586-- | A configurable generic @'Schema'@ creator.
669-- | A configurable generic @'Schema'@ creator.
587genericDeclareSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareSchemaUnrestricted") =>
670genericDeclareSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareSchemaUnrestricted") =>
588− SchemaOptions -> proxy a -> Declare (Definitions Schema) Schema
671+ SchemaOptions -> Proxy a -> Declare (Definitions Schema) Schema
589genericDeclareSchema = genericDeclareSchemaUnrestricted
672genericDeclareSchema = genericDeclareSchemaUnrestricted
591-- | A configurable generic @'NamedSchema'@ creator.
674-- | A configurable generic @'NamedSchema'@ creator.
592-- This function applied to @'defaultSchemaOptions'@
675-- This function applied to @'defaultSchemaOptions'@
593-- is used as the default for @'declareNamedSchema'@
676-- is used as the default for @'declareNamedSchema'@
594-- when the type is an instance of @'Generic'@.
677-- when the type is an instance of @'Generic'@.
595−genericDeclareNamedSchema :: forall a proxy. (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareNamedSchemaUnrestricted") =>
678+genericDeclareNamedSchema :: (Generic a, GToSchema (Rep a), TypeHasSimpleShape a "genericDeclareNamedSchemaUnrestricted") =>
596− SchemaOptions -> proxy a -> Declare (Definitions Schema) NamedSchema
679+ SchemaOptions -> Proxy a -> Declare (Definitions Schema) NamedSchema
597genericDeclareNamedSchema = genericDeclareNamedSchemaUnrestricted
680genericDeclareNamedSchema = genericDeclareNamedSchemaUnrestricted
599-- | A configurable generic @'Schema'@ creator.
682-- | A configurable generic @'Schema'@ creator.
601-- Unlike 'genericDeclareSchema' also works for mixed sum types.
684-- Unlike 'genericDeclareSchema' also works for mixed sum types.
602-- Use with care since some Swagger tools do not support well schemas for mixed sum types.
685-- 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
604genericDeclareSchemaUnrestricted opts proxy = _namedSchemaSchema <$> genericDeclareNamedSchemaUnrestricted opts proxy
687genericDeclareSchemaUnrestricted opts proxy = _namedSchemaSchema <$> genericDeclareNamedSchemaUnrestricted opts proxy
606-- | A configurable generic @'NamedSchema'@ creator.
689-- | A configurable generic @'NamedSchema'@ creator.
608-- Unlike 'genericDeclareNamedSchema' also works for mixed sum types.
691-- Unlike 'genericDeclareNamedSchema' also works for mixed sum types.
609-- Use with care since some Swagger tools do not support well schemas for mixed sum types.
692-- 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)) =>
693+genericDeclareNamedSchemaUnrestricted :: forall a. (Generic a, GToSchema (Rep a)) =>
611− SchemaOptions -> proxy a -> Declare (Definitions Schema) NamedSchema
694+ SchemaOptions -> Proxy a -> Declare (Definitions Schema) NamedSchema
612genericDeclareNamedSchemaUnrestricted opts _ = gdeclareNamedSchema opts (Proxy :: Proxy (Rep a)) mempty
695genericDeclareNamedSchemaUnrestricted opts _ = gdeclareNamedSchema opts (Proxy :: Proxy (Rep a)) mempty
614−gdatatypeSchemaName :: forall proxy d. Datatype d => SchemaOptions -> proxy d -> Maybe T.Text
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))
703+gdatatypeSchemaName :: forall d. Datatype d => SchemaOptions -> Proxy d -> Maybe T.Text
615−gdatatypeSchemaName opts _ = case name of
704+gdatatypeSchemaName opts _ = case orig of
616 (c:_) | isAlpha c && isUpper c -> Just (T.pack name)
705 (c:_) | isAlpha c && isUpper c -> Just (T.pack name)
617 _ -> Nothing
706 _ -> Nothing
619− name = datatypeNameModifier opts (datatypeName (Proxy3 :: Proxy3 d f a))
708+ orig = datatypeName (Proxy3 :: Proxy3 d f a)
709+ name = datatypeNameModifier opts orig
621-- | Lift a plain @'ParamSchema'@ into a model @'NamedSchema'@.
711-- | 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)
712+paramSchemaToNamedSchema :: (ToParamSchema a, Generic a, Rep a ~ D1 d f, Datatype d) =>
624− => SchemaOptions -> proxy a -> NamedSchema
713+ SchemaOptions -> Proxy a -> NamedSchema
625−paramSchemaToNamedSchema opts proxy = NamedSchema (gdatatypeSchemaName opts (Proxy :: Proxy d)) (paramSchemaToSchema proxy)
714+paramSchemaToNamedSchema opts proxy = genericNameSchema opts proxy (paramSchemaToSchema proxy)
627-- | Lift a plain @'ParamSchema'@ into a model @'Schema'@.
716-- | Lift a plain @'ParamSchema'@ into a model @'Schema'@.
628−paramSchemaToSchema :: forall a proxy. ToParamSchema a => proxy a -> Schema
717+paramSchemaToSchema :: ToParamSchema a => Proxy a -> Schema
629−paramSchemaToSchema _ = mempty & paramSchema .~ toParamSchema (Proxy :: Proxy a)
718+paramSchemaToSchema proxy = mempty & paramSchema .~ toParamSchema proxy
631nullarySchema :: Schema
720nullarySchema :: Schema
632nullarySchema = mempty
721nullarySchema = mempty
633− & type_ .~ SwaggerArray
722+ & type_ ?~ SwaggerArray
634 & items ?~ SwaggerItemsArray []
723 & items ?~ SwaggerItemsArray []
636−gtoNamedSchema :: GToSchema f => SchemaOptions -> proxy f -> NamedSchema
725+gtoNamedSchema :: GToSchema f => SchemaOptions -> Proxy f -> NamedSchema
637gtoNamedSchema opts proxy = undeclare $ gdeclareNamedSchema opts proxy mempty
726gtoNamedSchema opts proxy = undeclare $ gdeclareNamedSchema opts proxy mempty
639−gdeclareSchema :: GToSchema f => SchemaOptions -> proxy f -> Declare (Definitions Schema) Schema
728+gdeclareSchema :: GToSchema f => SchemaOptions -> Proxy f -> Declare (Definitions Schema) Schema
640gdeclareSchema opts proxy = _namedSchemaSchema <$> gdeclareNamedSchema opts proxy mempty
729gdeclareSchema opts proxy = _namedSchemaSchema <$> gdeclareNamedSchema opts proxy mempty
642instance (GToSchema f, GToSchema g) => GToSchema (f :*: g) where
731instance (GToSchema f, GToSchema g) => GToSchema (f :*: g) where
@@ -656,7 +745,7 @@ instance OVERLAPPING_ Constructor c => GToSchema (C1 c U1) where
656 gdeclareNamedSchema = gdeclareNamedSumSchema
745 gdeclareNamedSchema = gdeclareNamedSumSchema
658-- | Single field constructor.
747-- | 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
660 gdeclareNamedSchema opts _ s
749 gdeclareNamedSchema opts _ s
661 | unwrapUnaryRecords opts = fieldSchema
750 | unwrapUnaryRecords opts = fieldSchema
662 | otherwise =
751 | otherwise =
@@ -670,7 +759,7 @@ instance (Selector s, GToSchema f) => GToSchema (C1 c (S1 s f)) where
670 recordSchema = gdeclareNamedSchema opts (Proxy :: Proxy (S1 s f)) s
759 recordSchema = gdeclareNamedSchema opts (Proxy :: Proxy (S1 s f)) s
671 fieldSchema = gdeclareNamedSchema opts (Proxy :: Proxy f) s
760 fieldSchema = gdeclareNamedSchema opts (Proxy :: Proxy f) s
673−gdeclareSchemaRef :: GToSchema a => SchemaOptions -> proxy a -> Declare (Definitions Schema) (Referenced Schema)
762+gdeclareSchemaRef :: GToSchema a => SchemaOptions -> Proxy a -> Declare (Definitions Schema) (Referenced Schema)
674gdeclareSchemaRef opts proxy = do
763gdeclareSchemaRef opts proxy = do
675 case gtoNamedSchema opts proxy of
764 case gtoNamedSchema opts proxy of
676 NamedSchema (Just name) schema -> do
765 NamedSchema (Just name) schema -> do
@@ -701,12 +790,12 @@ withFieldSchema opts _ isRequiredField schema = do
702 if T.null fname
791 if T.null fname
703 then schema
792 then schema
704− & type_ .~ SwaggerArray
793+ & type_ ?~ SwaggerArray
705 & items %~ appendItem ref
794 & items %~ appendItem ref
706 & maxItems %~ Just . maybe 1 (+1) -- increment maxItems
795 & maxItems %~ Just . maybe 1 (+1) -- increment maxItems
707 & minItems %~ Just . maybe 1 (+1) -- increment minItems
796 & minItems %~ Just . maybe 1 (+1) -- increment minItems
708 else schema
797 else schema
709− & type_ .~ SwaggerObject
798+ & type_ ?~ SwaggerObject
710 & properties . at fname ?~ ref
799 & properties . at fname ?~ ref
711 & if isRequiredField
800 & if isRequiredField
712 then required %~ (++ [fname])
801 then required %~ (++ [fname])
@@ -734,7 +823,7 @@ instance ( GSumToSchema f
735 gdeclareNamedSchema = gdeclareNamedSumSchema
824 gdeclareNamedSchema = gdeclareNamedSumSchema
737−gdeclareNamedSumSchema :: GSumToSchema f => SchemaOptions -> proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
826+gdeclareNamedSumSchema :: GSumToSchema f => SchemaOptions -> Proxy f -> Schema -> Declare (Definitions Schema) NamedSchema
738gdeclareNamedSumSchema opts proxy s
827gdeclareNamedSumSchema opts proxy s
739 | allNullaryToStringTag opts && allNullary = pure $ unnamed (toStringTag sumSchema)
828 | allNullaryToStringTag opts && allNullary = pure $ unnamed (toStringTag sumSchema)
740 | otherwise = (unnamed . fst) <$> runWriterT declareSumSchema
829 | otherwise = (unnamed . fst) <$> runWriterT declareSumSchema
@@ -743,29 +832,29 @@ gdeclareNamedSumSchema opts proxy s
743 (sumSchema, All allNullary) = undeclare (runWriterT declareSumSchema)
832 (sumSchema, All allNullary) = undeclare (runWriterT declareSumSchema)
745 toStringTag schema = mempty
834 toStringTag schema = mempty
746− & type_ .~ SwaggerString
835+ & type_ ?~ SwaggerString
747 & enum_ ?~ map toJSON (schema ^.. properties.ifolded.asIndex)
836 & enum_ ?~ map toJSON (schema ^.. properties.ifolded.asIndex)
749type AllNullary = All
838type AllNullary = All
751class GSumToSchema (f :: * -> *) where
840class 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
754instance (GSumToSchema f, GSumToSchema g) => GSumToSchema (f :+: g) where
843instance (GSumToSchema f, GSumToSchema g) => GSumToSchema (f :+: g) where
755 gsumToSchema opts _ = gsumToSchema opts (Proxy :: Proxy f) >=> gsumToSchema opts (Proxy :: Proxy g)
844 gsumToSchema opts _ = gsumToSchema opts (Proxy :: Proxy f) >=> gsumToSchema opts (Proxy :: Proxy g)
757−gsumConToSchemaWith :: forall c f proxy. (GToSchema (C1 c f), Constructor c) =>
846+gsumConToSchemaWith :: forall c f. (GToSchema (C1 c f), Constructor c) =>
758− Referenced Schema -> SchemaOptions -> proxy (C1 c f) -> Schema -> Schema
847+ Referenced Schema -> SchemaOptions -> Proxy (C1 c f) -> Schema -> Schema
759gsumConToSchemaWith ref opts _ schema = schema
848gsumConToSchemaWith ref opts _ schema = schema
760− & type_ .~ SwaggerObject
849+ & type_ ?~ SwaggerObject
761 & properties . at tag ?~ ref
850 & properties . at tag ?~ ref
762 & maxProperties ?~ 1
851 & maxProperties ?~ 1
763 & minProperties ?~ 1
852 & minProperties ?~ 1
765 tag = T.pack (constructorTagModifier opts (conName (Proxy3 :: Proxy3 c f p)))
854 tag = T.pack (constructorTagModifier opts (conName (Proxy3 :: Proxy3 c f p)))
767−gsumConToSchema :: forall c f proxy. (GToSchema (C1 c f), Constructor c) =>
856+gsumConToSchema :: (GToSchema (C1 c f), Constructor c) =>
768− SchemaOptions -> proxy (C1 c f) -> Schema -> Declare (Definitions Schema) Schema
857+ SchemaOptions -> Proxy (C1 c f) -> Schema -> Declare (Definitions Schema) Schema
769gsumConToSchema opts proxy schema = do
858gsumConToSchema opts proxy schema = do
770 ref <- gdeclareSchemaRef opts proxy
859 ref <- gdeclareSchemaRef opts proxy
771 return $ gsumConToSchemaWith ref opts proxy schema
860 return $ gsumConToSchemaWith ref opts proxy schema
@@ -789,3 +878,5 @@ data Proxy3 a b c = Proxy3
791-- >>> import Data.Swagger
880-- >>> import Data.Swagger
881+-- >>> import Data.Aeson (encode)
882+-- >>> import Data.Aeson.Types (toJSONKeyText)