git.iko.soy/typeable/openapi3
on master help sign in
Doctests pass
27079c7Maxim Koltsov
src/Data/Swagger.hs+26−23
@@ -134,6 +134,7 @@ import Data.Swagger.Internal
134-- >>> import Data.Monoid
134-- >>> import Data.Monoid
135-- >>> import Data.Proxy
135-- >>> import Data.Proxy
136-- >>> import GHC.Generics
136-- >>> import GHC.Generics
137+-- >>> import qualified Data.ByteString.Lazy.Char8 as BSL
137-- >>> :set -XDeriveGeneric
138-- >>> :set -XDeriveGeneric
138-- >>> :set -XOverloadedStrings
139-- >>> :set -XOverloadedStrings
139-- >>> :set -XOverloadedLists
140-- >>> :set -XOverloadedLists
@@ -150,8 +151,8 @@ import Data.Swagger.Internal
150--
151--
151-- In this library you can use @'mempty'@ for a default/empty value. For instance:
152-- In this library you can use @'mempty'@ for a default/empty value. For instance:
152--
153--
153−-- >>> encode (mempty :: Swagger)
154+-- >>> BSL.putStrLn $ encode (mempty :: Swagger)
154−-- "{\"swagger\":\"2.0\",\"info\":{\"version\":\"\",\"title\":\"\"}}"
155+-- {"openapi":"3.0.0","info":{"version":"","title":""},"components":{}}
155--
156--
156-- As you can see some spec properties (e.g. @"version"@) are there even when the spec is empty.
157-- As you can see some spec properties (e.g. @"version"@) are there even when the spec is empty.
157-- That is because these properties are actually required ones.
158-- That is because these properties are actually required ones.
@@ -159,13 +160,13 @@ import Data.Swagger.Internal
159-- You /should/ always override the default (empty) value for these properties,
160-- You /should/ always override the default (empty) value for these properties,
160-- although it is not strictly necessary:
161-- although it is not strictly necessary:
161--
162--
162−-- >>> encode mempty { _infoTitle = "Todo API", _infoVersion = "1.0" }
163+-- >>> BSL.putStrLn $ encode mempty { _infoTitle = "Todo API", _infoVersion = "1.0" }
163−-- "{\"version\":\"1.0\",\"title\":\"Todo API\"}"
164+-- {"version":"1.0","title":"Todo API"}
164--
165--
165-- You can merge two values using @'mappend'@ or its infix version @('<>')@:
166-- You can merge two values using @'mappend'@ or its infix version @('<>')@:
166--
167--
167−-- >>> encode $ mempty { _infoTitle = "Todo API" } <> mempty { _infoVersion = "1.0" }
168+-- >>> BSL.putStrLn $ encode $ mempty { _infoTitle = "Todo API" } <> mempty { _infoVersion = "1.0" }
168−-- "{\"version\":\"1.0\",\"title\":\"Todo API\"}"
169+-- {"version":"1.0","title":"Todo API"}
169--
170--
170-- This can be useful for combining specifications of endpoints into a whole API specification:
171-- This can be useful for combining specifications of endpoints into a whole API specification:
171--
172--
@@ -191,15 +192,14 @@ import Data.Swagger.Internal
191-- make it fairly simple to construct/modify any part of the specification:
192-- make it fairly simple to construct/modify any part of the specification:
192--
193--
193-- >>> :{
194-- >>> :{
194−-- encode $ (mempty :: Swagger)
195+-- BSL.putStrLn $ encode $ (mempty :: Swagger)
195−-- & definitions .~ [ ("User", mempty & type_ ?~ SwaggerString) ]
196+-- & components . schemas .~ [ ("User", mempty & type_ ?~ SwaggerString) ]
196-- & paths .~
197-- & paths .~
197-- [ ("/user", mempty & get ?~ (mempty
198-- [ ("/user", mempty & get ?~ (mempty
198−-- & produces ?~ MimeList ["application/json"]
199−-- & at 200 ?~ ("OK" & _Inline.schema ?~ Ref (Reference "User"))
199+-- & at 200 ?~ ("OK" & _Inline.content.at "application/json" ?~ (mempty & schema ?~ Ref (Reference "User")))
200-- & at 404 ?~ "User info not found")) ]
200-- & at 404 ?~ "User info not found")) ]
201-- :}
201-- :}
202−-- "{\"swagger\":\"2.0\",\"info\":{\"version\":\"\",\"title\":\"\"},\"paths\":{\"/user\":{\"get\":{\"produces\":[\"application/json\"],\"responses\":{\"404\":{\"description\":\"User info not found\"},\"200\":{\"schema\":{\"$ref\":\"#/definitions/User\"},\"description\":\"OK\"}}}}},\"definitions\":{\"User\":{\"type\":\"string\"}}}"
202+-- {"openapi":"3.0.0","info":{"version":"","title":""},"paths":{"/user":{"get":{"responses":{"404":{"description":"User info not found"},"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}},"description":"OK"}}}}},"components":{"schemas":{"User":{"type":"string"}}}}
203--
203--
204-- In the snippet above we declare an API with a single path @/user@. This path provides method @GET@
204-- In the snippet above we declare an API with a single path @/user@. This path provides method @GET@
205-- which produces @application/json@ output. It should respond with code @200@ and body specified
205-- which produces @application/json@ output. It should respond with code @200@ and body specified
@@ -211,30 +211,33 @@ import Data.Swagger.Internal
211-- common field is @'description'@. Many components of a Swagger specification
211-- common field is @'description'@. Many components of a Swagger specification
212-- can have descriptions, and you can use the same name for them:
212-- can have descriptions, and you can use the same name for them:
213--
213--
214−-- >>> encode $ (mempty :: Response) & description .~ "No content"
214+-- >>> BSL.putStrLn $ encode $ (mempty :: Response) & description .~ "No content"
215−-- "{\"description\":\"No content\"}"
215+-- {"description":"No content"}
216-- >>> :{
216-- >>> :{
217−-- encode $ (mempty :: Schema)
217+-- BSL.putStrLn $ encode $ (mempty :: Schema)
218-- & type_ ?~ SwaggerBoolean
218-- & type_ ?~ SwaggerBoolean
219-- & description ?~ "To be or not to be"
219-- & description ?~ "To be or not to be"
220-- :}
220-- :}
221−-- "{\"description\":\"To be or not to be\",\"type\":\"boolean\"}"
221+-- {"description":"To be or not to be","type":"boolean"}
222--
222--
223-- @'ParamSchema'@ is basically the /base schema specification/ and many types contain it (see @'HasParamSchema'@).
223-- @'ParamSchema'@ is basically the /base schema specification/ and many types contain it (see @'HasParamSchema'@).
224-- So for convenience, all @'ParamSchema'@ fields are transitively made fields of the type that has it.
224-- So for convenience, all @'ParamSchema'@ fields are transitively made fields of the type that has it.
225-- For example, you can use @'type_'@ to access @'SwaggerType'@ of @'Header'@ schema without having to use @'paramSchema'@:
225-- For example, you can use @'type_'@ to access @'SwaggerType'@ of @'Header'@ schema without having to use @'paramSchema'@:
226--
226--
227−-- >>> encode $ (mempty :: Header) & type_ ?~ SwaggerNumber
227+-- >>> BSL.putStrLn $ encode $ (mempty :: Header) & type_ ?~ SwaggerNumber
228−-- "{\"type\":\"number\"}"
228+-- {"schema":{"type":"number"}}
229+--
230+-- TODO this is no up-to-date ^, since in openapi 3 there is no ParamSchema madness, all objects
231+-- have Schemas as fields.
229--
232--
230-- Additionally, to simplify working with @'Response'@, both @'Operation'@ and @'Responses'@
233-- Additionally, to simplify working with @'Response'@, both @'Operation'@ and @'Responses'@
231-- have direct access to it via @'at' code@. Example:
234-- have direct access to it via @'at' code@. Example:
232--
235--
233-- >>> :{
236-- >>> :{
234−-- encode $ (mempty :: Operation)
237+-- BSL.putStrLn $ encode $ (mempty :: Operation)
235-- & at 404 ?~ "Not found"
238-- & at 404 ?~ "Not found"
236-- :}
239-- :}
237−-- "{\"responses\":{\"404\":{\"description\":\"Not found\"}}}"
240+-- {"responses":{"404":{"description":"Not found"}}}
238--
241--
239-- You might've noticed that @'type_'@ has an extra underscore in its name
242-- You might've noticed that @'type_'@ has an extra underscore in its name
240-- compared to, say, @'description'@ field accessor.
243-- compared to, say, @'description'@ field accessor.
@@ -281,10 +284,10 @@ import Data.Swagger.Internal
281-- >>> data Person = Person { name :: String, age :: Integer } deriving Generic
284-- >>> data Person = Person { name :: String, age :: Integer } deriving Generic
282-- >>> instance ToJSON Person
285-- >>> instance ToJSON Person
283-- >>> instance ToSchema Person
286-- >>> instance ToSchema Person
284−-- >>> encode (Person "David" 28)
287+-- >>> BSL.putStrLn $ encode (Person "David" 28)
285−-- "{\"age\":28,\"name\":\"David\"}"
288+-- {"age":28,"name":"David"}
286−-- >>> encode $ toSchema (Proxy :: Proxy Person)
289+-- >>> BSL.putStrLn $ encode $ toSchema (Proxy :: Proxy Person)
287−-- "{\"required\":[\"name\",\"age\"],\"properties\":{\"name\":{\"type\":\"string\"},\"age\":{\"type\":\"integer\"}},\"type\":\"object\"}"
290+-- {"required":["name","age"],"properties":{"name":{"type":"string"},"age":{"type":"integer"}},"type":"object"}
288--
291--
289-- Please note that not all valid Haskell data types will have a proper swagger schema. For example while we can derive a
292-- Please note that not all valid Haskell data types will have a proper swagger schema. For example while we can derive a
290-- schema for basic enums like
293-- schema for basic enums like
src/Data/Swagger/Internal.hs+2−2
@@ -1427,10 +1427,10 @@ instance FromJSON (SwaggerItems 'SwaggerKindParamOtherSchema) where
1427-- >>> decode "{}" :: Maybe (SwaggerItems 'SwaggerKindSchema)
1427-- >>> decode "{}" :: Maybe (SwaggerItems 'SwaggerKindSchema)
1428-- Just (SwaggerItemsArray [])
1428-- Just (SwaggerItemsArray [])
1429--
1429--
1430−-- >>> eitherDecode "{\"$ref\":\"#/definitions/example\"}" :: Either String (SwaggerItems 'SwaggerKindSchema)
1430+-- >>> eitherDecode "{\"$ref\":\"#/components/schemas/example\"}" :: Either String (SwaggerItems 'SwaggerKindSchema)
1431-- Right (SwaggerItemsObject (Ref (Reference {getReference = "example"})))
1431-- Right (SwaggerItemsObject (Ref (Reference {getReference = "example"})))
1432--
1432--
1433−-- >>> eitherDecode "[{\"$ref\":\"#/definitions/example\"}]" :: Either String (SwaggerItems 'SwaggerKindSchema)
1433+-- >>> eitherDecode "[{\"$ref\":\"#/components/schemas/example\"}]" :: Either String (SwaggerItems 'SwaggerKindSchema)
1434-- Right (SwaggerItemsArray [Ref (Reference {getReference = "example"})])
1434-- Right (SwaggerItemsArray [Ref (Reference {getReference = "example"})])
1435--
1435--
1436instance FromJSON (SwaggerItems 'SwaggerKindSchema) where
1436instance FromJSON (SwaggerItems 'SwaggerKindSchema) where
src/Data/Swagger/Internal/Schema.hs+37−37
@@ -67,7 +67,7 @@ import Data.Swagger.SchemaOptions
67import Data.Swagger.Internal.TypeShape
67import Data.Swagger.Internal.TypeShape
68
68
69import qualified Data.ByteString as BS
69import qualified Data.ByteString as BS
70−import qualified Data.ByteString.Lazy as BSL
70+import qualified Data.ByteString.Lazy.Char8 as BSL
71import GHC.TypeLits (TypeError, ErrorMessage(..))
71import GHC.TypeLits (TypeError, ErrorMessage(..))
72
72
73unnamed :: Schema -> NamedSchema
73unnamed :: Schema -> NamedSchema
@@ -151,13 +151,13 @@ declareSchema = fmap _namedSchemaSchema . declareNamedSchema
151--
151--
152-- >>> toNamedSchema (Proxy :: Proxy String) ^. name
152-- >>> toNamedSchema (Proxy :: Proxy String) ^. name
153-- Nothing
153-- Nothing
154−-- >>> encode (toNamedSchema (Proxy :: Proxy String) ^. schema)
154+-- >>> BSL.putStrLn $ encode (toNamedSchema (Proxy :: Proxy String) ^. schema)
155−-- "{\"type\":\"string\"}"
155+-- {"type":"string"}
156--
156--
157-- >>> toNamedSchema (Proxy :: Proxy Day) ^. name
157-- >>> toNamedSchema (Proxy :: Proxy Day) ^. name
158-- Just "Day"
158-- Just "Day"
159−-- >>> encode (toNamedSchema (Proxy :: Proxy Day) ^. schema)
159+-- >>> BSL.putStrLn $ encode (toNamedSchema (Proxy :: Proxy Day) ^. schema)
160−-- "{\"example\":\"2016-07-22\",\"format\":\"date\",\"type\":\"string\"}"
160+-- {"example":"2016-07-22","format":"date","type":"string"}
161toNamedSchema :: ToSchema a => Proxy a -> NamedSchema
161toNamedSchema :: ToSchema a => Proxy a -> NamedSchema
162toNamedSchema = undeclare . declareNamedSchema
162toNamedSchema = undeclare . declareNamedSchema
163
163
@@ -173,22 +173,22 @@ schemaName = _namedSchemaName . toNamedSchema
173
173
174-- | Convert a type into a schema.
174-- | Convert a type into a schema.
175--
175--
176−-- >>> encode $ toSchema (Proxy :: Proxy Int8)
176+-- >>> BSL.putStrLn $ encode $ toSchema (Proxy :: Proxy Int8)
177−-- "{\"maximum\":127,\"minimum\":-128,\"type\":\"integer\"}"
177+-- {"maximum":127,"minimum":-128,"type":"integer"}
178--
178--
179−-- >>> encode $ toSchema (Proxy :: Proxy [Day])
179+-- >>> BSL.putStrLn $ encode $ toSchema (Proxy :: Proxy [Day])
180−-- "{\"items\":{\"$ref\":\"#/definitions/Day\"},\"type\":\"array\"}"
180+-- {"items":{"$ref":"#/components/schemas/Day"},"type":"array"}
181toSchema :: ToSchema a => Proxy a -> Schema
181toSchema :: ToSchema a => Proxy a -> Schema
182toSchema = _namedSchemaSchema . toNamedSchema
182toSchema = _namedSchemaSchema . toNamedSchema
183
183
184-- | Convert a type into a referenced schema if possible.
184-- | Convert a type into a referenced schema if possible.
185-- Only named schemas can be referenced, nameless schemas are inlined.
185-- Only named schemas can be referenced, nameless schemas are inlined.
186--
186--
187−-- >>> encode $ toSchemaRef (Proxy :: Proxy Integer)
187+-- >>> BSL.putStrLn $ encode $ toSchemaRef (Proxy :: Proxy Integer)
188−-- "{\"type\":\"integer\"}"
188+-- {"type":"integer"}
189--
189--
190−-- >>> encode $ toSchemaRef (Proxy :: Proxy Day)
190+-- >>> BSL.putStrLn $ encode $ toSchemaRef (Proxy :: Proxy Day)
191−-- "{\"$ref\":\"#/definitions/Day\"}"
191+-- {"$ref":"#/components/schemas/Day"}
192toSchemaRef :: ToSchema a => Proxy a -> Referenced Schema
192toSchemaRef :: ToSchema a => Proxy a -> Referenced Schema
193toSchemaRef = undeclare . declareSchemaRef
193toSchemaRef = undeclare . declareSchemaRef
194
194
@@ -256,8 +256,8 @@ inlineAllSchemas = inlineSchemasWhen (const True)
256
256
257-- | Convert a type into a schema without references.
257-- | Convert a type into a schema without references.
258--
258--
259−-- >>> encode $ toInlinedSchema (Proxy :: Proxy [Day])
259+-- >>> BSL.putStrLn $ encode $ toInlinedSchema (Proxy :: Proxy [Day])
260−-- "{\"items\":{\"example\":\"2016-07-22\",\"format\":\"date\",\"type\":\"string\"},\"type\":\"array\"}"
260+-- {"items":{"example":"2016-07-22","format":"date","type":"string"},"type":"array"}
261--
261--
262-- __WARNING:__ @'toInlinedSchema'@ will produce infinite schema
262-- __WARNING:__ @'toInlinedSchema'@ will produce infinite schema
263-- when inlining recursive schemas.
263-- when inlining recursive schemas.
@@ -309,19 +309,19 @@ passwordSchema = mempty
309-- | Make an unrestrictive sketch of a @'Schema'@ based on a @'ToJSON'@ instance.
309-- | Make an unrestrictive sketch of a @'Schema'@ based on a @'ToJSON'@ instance.
310-- Produced schema can be used for further refinement.
310-- Produced schema can be used for further refinement.
311--
311--
312−-- >>> encode $ sketchSchema "hello"
312+-- >>> BSL.putStrLn $ encode $ sketchSchema "hello"
313−-- "{\"example\":\"hello\",\"type\":\"string\"}"
313+-- {"example":"hello","type":"string"}
314--
314--
315−-- >>> encode $ sketchSchema (1, 2, 3)
315+-- >>> BSL.putStrLn $ encode $ sketchSchema (1, 2, 3)
316−-- "{\"example\":[1,2,3],\"items\":{\"type\":\"number\"},\"type\":\"array\"}"
316+-- {"example":[1,2,3],"items":{"type":"number"},"type":"array"}
317--
317--
318−-- >>> encode $ sketchSchema ("Jack", 25)
318+-- >>> BSL.putStrLn $ encode $ sketchSchema ("Jack", 25)
319−-- "{\"example\":[\"Jack\",25],\"items\":[{\"type\":\"string\"},{\"type\":\"number\"}],\"type\":\"array\"}"
319+-- {"example":["Jack",25],"items":[{"type":"string"},{"type":"number"}],"type":"array"}
320--
320--
321-- >>> data Person = Person { name :: String, age :: Int } deriving (Generic)
321-- >>> data Person = Person { name :: String, age :: Int } deriving (Generic)
322-- >>> instance ToJSON Person
322-- >>> instance ToJSON Person
323−-- >>> encode $ sketchSchema (Person "Jack" 25)
323+-- >>> BSL.putStrLn $ encode $ sketchSchema (Person "Jack" 25)
324−-- "{\"required\":[\"age\",\"name\"],\"properties\":{\"age\":{\"type\":\"number\"},\"name\":{\"type\":\"string\"}},\"example\":{\"age\":25,\"name\":\"Jack\"},\"type\":\"object\"}"
324+-- {"required":["age","name"],"properties":{"age":{"type":"number"},"name":{"type":"string"}},"example":{"age":25,"name":"Jack"},"type":"object"}
325sketchSchema :: ToJSON a => a -> Schema
325sketchSchema :: ToJSON a => a -> Schema
326sketchSchema = sketch . toJSON
326sketchSchema = sketch . toJSON
327 where
327 where
@@ -353,19 +353,19 @@ sketchSchema = sketch . toJSON
353-- | Make a restrictive sketch of a @'Schema'@ based on a @'ToJSON'@ instance.
353-- | Make a restrictive sketch of a @'Schema'@ based on a @'ToJSON'@ instance.
354-- Produced schema uses as much constraints as possible.
354-- Produced schema uses as much constraints as possible.
355--
355--
356−-- >>> encode $ sketchStrictSchema "hello"
356+-- >>> BSL.putStrLn $ encode $ sketchStrictSchema "hello"
357−-- "{\"maxLength\":5,\"pattern\":\"hello\",\"minLength\":5,\"type\":\"string\",\"enum\":[\"hello\"]}"
357+-- {"maxLength":5,"pattern":"hello","minLength":5,"type":"string","enum":["hello"]}
358--
358--
359−-- >>> encode $ sketchStrictSchema (1, 2, 3)
359+-- >>> BSL.putStrLn $ encode $ sketchStrictSchema (1, 2, 3)
360−-- "{\"minItems\":3,\"uniqueItems\":true,\"items\":[{\"maximum\":1,\"minimum\":1,\"multipleOf\":1,\"type\":\"number\",\"enum\":[1]},{\"maximum\":2,\"minimum\":2,\"multipleOf\":2,\"type\":\"number\",\"enum\":[2]},{\"maximum\":3,\"minimum\":3,\"multipleOf\":3,\"type\":\"number\",\"enum\":[3]}],\"maxItems\":3,\"type\":\"array\",\"enum\":[[1,2,3]]}"
360+-- {"minItems":3,"uniqueItems":true,"items":[{"maximum":1,"minimum":1,"multipleOf":1,"type":"number","enum":[1]},{"maximum":2,"minimum":2,"multipleOf":2,"type":"number","enum":[2]},{"maximum":3,"minimum":3,"multipleOf":3,"type":"number","enum":[3]}],"maxItems":3,"type":"array","enum":[[1,2,3]]}
361--
361--
362−-- >>> encode $ sketchStrictSchema ("Jack", 25)
362+-- >>> BSL.putStrLn $ encode $ sketchStrictSchema ("Jack", 25)
363−-- "{\"minItems\":2,\"uniqueItems\":true,\"items\":[{\"maxLength\":4,\"pattern\":\"Jack\",\"minLength\":4,\"type\":\"string\",\"enum\":[\"Jack\"]},{\"maximum\":25,\"minimum\":25,\"multipleOf\":25,\"type\":\"number\",\"enum\":[25]}],\"maxItems\":2,\"type\":\"array\",\"enum\":[[\"Jack\",25]]}"
363+-- {"minItems":2,"uniqueItems":true,"items":[{"maxLength":4,"pattern":"Jack","minLength":4,"type":"string","enum":["Jack"]},{"maximum":25,"minimum":25,"multipleOf":25,"type":"number","enum":[25]}],"maxItems":2,"type":"array","enum":[["Jack",25]]}
364--
364--
365-- >>> data Person = Person { name :: String, age :: Int } deriving (Generic)
365-- >>> data Person = Person { name :: String, age :: Int } deriving (Generic)
366-- >>> instance ToJSON Person
366-- >>> instance ToJSON Person
367−-- >>> encode $ sketchStrictSchema (Person "Jack" 25)
367+-- >>> BSL.putStrLn $ encode $ sketchStrictSchema (Person "Jack" 25)
368−-- "{\"required\":[\"age\",\"name\"],\"properties\":{\"age\":{\"maximum\":25,\"minimum\":25,\"multipleOf\":25,\"type\":\"number\",\"enum\":[25]},\"name\":{\"maxLength\":4,\"pattern\":\"Jack\",\"minLength\":4,\"type\":\"string\",\"enum\":[\"Jack\"]}},\"maxProperties\":2,\"minProperties\":2,\"type\":\"object\",\"enum\":[{\"age\":25,\"name\":\"Jack\"}]}"
368+-- {"required":["age","name"],"properties":{"age":{"maximum":25,"minimum":25,"multipleOf":25,"type":"number","enum":[25]},"name":{"maxLength":4,"pattern":"Jack","minLength":4,"type":"string","enum":["Jack"]}},"maxProperties":2,"minProperties":2,"type":"object","enum":[{"age":25,"name":"Jack"}]}
369sketchStrictSchema :: ToJSON a => a -> Schema
369sketchStrictSchema :: ToJSON a => a -> Schema
370sketchStrictSchema = go . toJSON
370sketchStrictSchema = go . toJSON
371 where
371 where
@@ -565,8 +565,8 @@ instance ToSchema a => ToSchema (Identity a) where declareNamedSchema _ = declar
565
565
566-- | Default schema for @'Bounded'@, @'Integral'@ types.
566-- | Default schema for @'Bounded'@, @'Integral'@ types.
567--
567--
568−-- >>> encode $ toSchemaBoundedIntegral (Proxy :: Proxy Int16)
568+-- >>> BSL.putStrLn $ encode $ toSchemaBoundedIntegral (Proxy :: Proxy Int16)
569−-- "{\"maximum\":32767,\"minimum\":-32768,\"type\":\"integer\"}"
569+-- {"maximum":32767,"minimum":-32768,"type":"integer"}
570toSchemaBoundedIntegral :: forall a. (Bounded a, Integral a) => Proxy a -> Schema
570toSchemaBoundedIntegral :: forall a. (Bounded a, Integral a) => Proxy a -> Schema
571toSchemaBoundedIntegral _ = mempty
571toSchemaBoundedIntegral _ = mempty
572 & type_ ?~ SwaggerInteger
572 & type_ ?~ SwaggerInteger
@@ -598,8 +598,8 @@ genericDeclareNamedSchemaNewtype opts f proxy = genericNameSchema opts proxy <$>
598-- >>> instance ToSchema ButtonState
598-- >>> instance ToSchema ButtonState
599-- >>> instance ToJSONKey ButtonState where toJSONKey = toJSONKeyText (T.pack . show)
599-- >>> instance ToJSONKey ButtonState where toJSONKey = toJSONKeyText (T.pack . show)
600-- >>> type ImageUrl = T.Text
600-- >>> type ImageUrl = T.Text
601−-- >>> encode $ toSchemaBoundedEnumKeyMapping (Proxy :: Proxy (Map ButtonState ImageUrl))
601+-- >>> BSL.putStrLn $ encode $ toSchemaBoundedEnumKeyMapping (Proxy :: Proxy (Map ButtonState ImageUrl))
602−-- "{\"properties\":{\"Neutral\":{\"type\":\"string\"},\"Focus\":{\"type\":\"string\"},\"Active\":{\"type\":\"string\"},\"Hover\":{\"type\":\"string\"},\"Disabled\":{\"type\":\"string\"}},\"type\":\"object\"}"
602+-- {"properties":{"Neutral":{"type":"string"},"Focus":{"type":"string"},"Active":{"type":"string"},"Hover":{"type":"string"},"Disabled":{"type":"string"}},"type":"object"}
603--
603--
604-- Note: this is only useful when @key@ is encoded with 'ToJSONKeyText'.
604-- Note: this is only useful when @key@ is encoded with 'ToJSONKeyText'.
605-- If it is encoded with 'ToJSONKeyValue' then a regular schema for @[(key, value)]@ is used.
605-- If it is encoded with 'ToJSONKeyValue' then a regular schema for @[(key, value)]@ is used.
@@ -626,8 +626,8 @@ declareSchemaBoundedEnumKeyMapping _ = case toJSONKey :: ToJSONKeyFunction key o
626-- >>> instance ToSchema ButtonState
626-- >>> instance ToSchema ButtonState
627-- >>> instance ToJSONKey ButtonState where toJSONKey = toJSONKeyText (T.pack . show)
627-- >>> instance ToJSONKey ButtonState where toJSONKey = toJSONKeyText (T.pack . show)
628-- >>> type ImageUrl = T.Text
628-- >>> type ImageUrl = T.Text
629−-- >>> encode $ toSchemaBoundedEnumKeyMapping (Proxy :: Proxy (Map ButtonState ImageUrl))
629+-- >>> BSL.putStrLn $ encode $ toSchemaBoundedEnumKeyMapping (Proxy :: Proxy (Map ButtonState ImageUrl))
630−-- "{\"properties\":{\"Neutral\":{\"type\":\"string\"},\"Focus\":{\"type\":\"string\"},\"Active\":{\"type\":\"string\"},\"Hover\":{\"type\":\"string\"},\"Disabled\":{\"type\":\"string\"}},\"type\":\"object\"}"
630+-- {"properties":{"Neutral":{"type":"string"},"Focus":{"type":"string"},"Active":{"type":"string"},"Hover":{"type":"string"},"Disabled":{"type":"string"}},"type":"object"}
631--
631--
632-- Note: this is only useful when @key@ is encoded with 'ToJSONKeyText'.
632-- Note: this is only useful when @key@ is encoded with 'ToJSONKeyText'.
633-- If it is encoded with 'ToJSONKeyValue' then a regular schema for @[(key, value)]@ is used.
633-- If it is encoded with 'ToJSONKeyValue' then a regular schema for @[(key, value)]@ is used.
src/Data/Swagger/Internal/Schema/Validation.hs+1−1
@@ -109,7 +109,7 @@ validateToJSONWithPatternChecker checker = validateJSONWithPatternChecker checke
109-- "type": "object",
109-- "type": "object",
110-- "properties": {
110-- "properties": {
111-- "phone": {
111-- "phone": {
112−-- "$ref": "#/definitions/Phone"
112+-- "$ref": "#/components/schemas/Phone"
113-- },
113-- },
114-- "name": {
114-- "name": {
115-- "type": "string"
115-- "type": "string"
src/Data/Swagger/Operation.hs+12−11
@@ -53,13 +53,14 @@ import qualified Data.HashSet.InsOrd as InsOrdHS
53-- >>> import Data.Aeson
53-- >>> import Data.Aeson
54-- >>> import Data.Proxy
54-- >>> import Data.Proxy
55-- >>> import Data.Time
55-- >>> import Data.Time
56+-- >>> import qualified Data.ByteString.Lazy.Char8 as BSL
56
57
57-- | Prepend path piece to all operations of the spec.
58-- | Prepend path piece to all operations of the spec.
58-- Leading and trailing slashes are trimmed/added automatically.
59-- Leading and trailing slashes are trimmed/added automatically.
59--
60--
60-- >>> let api = (mempty :: Swagger) & paths .~ [("/info", mempty)]
61-- >>> let api = (mempty :: Swagger) & paths .~ [("/info", mempty)]
61−-- >>> encode $ prependPath "user/{user_id}" api ^. paths
62+-- >>> BSL.putStrLn $ encode $ prependPath "user/{user_id}" api ^. paths
62−-- "{\"/user/{user_id}/info\":{}}"
63+-- {"/user/{user_id}/info":{}}
63prependPath :: FilePath -> Swagger -> Swagger
64prependPath :: FilePath -> Swagger -> Swagger
64prependPath path = paths %~ InsOrdHashMap.mapKeys (path </>)
65prependPath path = paths %~ InsOrdHashMap.mapKeys (path </>)
65 where
66 where
@@ -80,10 +81,10 @@ allOperations = paths.traverse.template
80-- >>> let ok = (mempty :: Operation) & at 200 ?~ "OK"
81-- >>> let ok = (mempty :: Operation) & at 200 ?~ "OK"
81-- >>> let api = (mempty :: Swagger) & paths .~ [("/user", mempty & get ?~ ok & post ?~ ok)]
82-- >>> let api = (mempty :: Swagger) & paths .~ [("/user", mempty & get ?~ ok & post ?~ ok)]
82-- >>> let sub = (mempty :: Swagger) & paths .~ [("/user", mempty & get ?~ mempty)]
83-- >>> let sub = (mempty :: Swagger) & paths .~ [("/user", mempty & get ?~ mempty)]
83−-- >>> encode api
84+-- >>> BSL.putStrLn $ encode api
84−-- "{\"swagger\":\"2.0\",\"info\":{\"version\":\"\",\"title\":\"\"},\"paths\":{\"/user\":{\"get\":{\"responses\":{\"200\":{\"description\":\"OK\"}}},\"post\":{\"responses\":{\"200\":{\"description\":\"OK\"}}}}}}"
85+-- {"openapi":"3.0.0","info":{"version":"","title":""},"paths":{"/user":{"get":{"responses":{"200":{"description":"OK"}}},"post":{"responses":{"200":{"description":"OK"}}}}},"components":{}}
85−-- >>> encode $ api & operationsOf sub . at 404 ?~ "Not found"
86+-- >>> BSL.putStrLn $ encode $ api & operationsOf sub . at 404 ?~ "Not found"
86−-- "{\"swagger\":\"2.0\",\"info\":{\"version\":\"\",\"title\":\"\"},\"paths\":{\"/user\":{\"get\":{\"responses\":{\"404\":{\"description\":\"Not found\"},\"200\":{\"description\":\"OK\"}}},\"post\":{\"responses\":{\"200\":{\"description\":\"OK\"}}}}}}"
87+-- {"openapi":"3.0.0","info":{"version":"","title":""},"paths":{"/user":{"get":{"responses":{"404":{"description":"Not found"},"200":{"description":"OK"}}},"post":{"responses":{"200":{"description":"OK"}}}}},"components":{}}
87operationsOf :: Swagger -> Traversal' Swagger Operation
88operationsOf :: Swagger -> Traversal' Swagger Operation
88operationsOf sub = paths.itraversed.withIndex.subops
89operationsOf sub = paths.itraversed.withIndex.subops
89 where
90 where
@@ -121,8 +122,8 @@ applyTagsFor ops ts swag = swag
121--
122--
122-- FIXME doc
123-- FIXME doc
123--
124--
124−-- >>> encode $ runDeclare (declareResponse (Proxy :: Proxy Day)) mempty
125+-- >>> BSL.putStrLn $ encode $ runDeclare (declareResponse "application/json" (Proxy :: Proxy Day)) mempty
125−-- "[{\"Day\":{\"example\":\"2016-07-22\",\"format\":\"date\",\"type\":\"string\"}},{\"description\":\"\",\"schema\":{\"$ref\":\"#/definitions/Day\"}}]"
126+-- [{"Day":{"example":"2016-07-22","format":"date","type":"string"}},{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Day"}}}}]
126declareResponse :: ToSchema a => Text -> Proxy a -> Declare (Definitions Schema) Response
127declareResponse :: ToSchema a => Text -> Proxy a -> Declare (Definitions Schema) Response
127declareResponse cType proxy = do
128declareResponse cType proxy = do
128 s <- declareSchemaRef proxy
129 s <- declareSchemaRef proxy
@@ -140,9 +141,9 @@ declareResponse cType proxy = do
140-- Example:
141-- Example:
141--
142--
142-- >>> let api = (mempty :: Swagger) & paths .~ [("/user", mempty & get ?~ mempty)]
143-- >>> let api = (mempty :: Swagger) & paths .~ [("/user", mempty & get ?~ mempty)]
143−-- >>> let res = declareResponse (Proxy :: Proxy Day)
144+-- >>> let res = declareResponse "application/json" (Proxy :: Proxy Day)
144−-- >>> encode $ api & setResponse 200 res
145+-- >>> BSL.putStrLn $ encode $ api & setResponse 200 res
145−-- "{\"swagger\":\"2.0\",\"info\":{\"version\":\"\",\"title\":\"\"},\"paths\":{\"/user\":{\"get\":{\"responses\":{\"200\":{\"schema\":{\"$ref\":\"#/definitions/Day\"},\"description\":\"\"}}}}},\"definitions\":{\"Day\":{\"example\":\"2016-07-22\",\"format\":\"date\",\"type\":\"string\"}}}"
146+-- {"openapi":"3.0.0","info":{"version":"","title":""},"paths":{"/user":{"get":{"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Day"}}},"description":""}}}}},"components":{"schemas":{"Day":{"example":"2016-07-22","format":"date","type":"string"}}}}
146--
147--
147-- See also @'setResponseWith'@.
148-- See also @'setResponseWith'@.
148setResponse :: HttpStatusCode -> Declare (Definitions Schema) Response -> Swagger -> Swagger
149setResponse :: HttpStatusCode -> Declare (Definitions Schema) Response -> Swagger -> Swagger
src/Data/Swagger/Optics.hs+13−13
@@ -17,33 +17,33 @@
17-- >>> import Data.Aeson
17-- >>> import Data.Aeson
18-- >>> import Optics.Core
18-- >>> import Optics.Core
19-- >>> :set -XOverloadedLabels
19-- >>> :set -XOverloadedLabels
20+-- >>> import qualified Data.ByteString.Lazy.Char8 as BSL
20--
21--
21-- Example from the "Data.Swagger" module using @optics@:
22-- Example from the "Data.Swagger" module using @optics@:
22--
23--
23-- >>> :{
24-- >>> :{
24−-- encode $ (mempty :: Swagger)
25+-- BSL.putStrLn $ encode $ (mempty :: Swagger)
25−-- & #definitions .~ [ ("User", mempty & #type ?~ SwaggerString) ]
26+-- & #components % #schemas .~ [ ("User", mempty & #type ?~ SwaggerString) ]
26-- & #paths .~
27-- & #paths .~
27-- [ ("/user", mempty & #get ?~ (mempty
28-- [ ("/user", mempty & #get ?~ (mempty
28−-- & #produces ?~ MimeList ["application/json"]
29−-- & at 200 ?~ ("OK" & #_Inline % #schema ?~ Ref (Reference "User"))
29+-- & at 200 ?~ ("OK" & #_Inline % #content % at "application/json" ?~ (mempty & #schema ?~ Ref (Reference "User")))
30-- & at 404 ?~ "User info not found")) ]
30-- & at 404 ?~ "User info not found")) ]
31-- :}
31-- :}
32−-- "{\"swagger\":\"2.0\",\"info\":{\"version\":\"\",\"title\":\"\"},\"paths\":{\"/user\":{\"get\":{\"produces\":[\"application/json\"],\"responses\":{\"404\":{\"description\":\"User info not found\"},\"200\":{\"schema\":{\"$ref\":\"#/definitions/User\"},\"description\":\"OK\"}}}}},\"definitions\":{\"User\":{\"type\":\"string\"}}}"
32+-- {"openapi":"3.0.0","info":{"version":"","title":""},"paths":{"/user":{"get":{"responses":{"404":{"description":"User info not found"},"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}},"description":"OK"}}}}},"components":{"schemas":{"User":{"type":"string"}}}}
33--
33--
34-- For convenience optics are defined as /labels/. It means that field accessor
34-- For convenience optics are defined as /labels/. It means that field accessor
35-- names can be overloaded for different types. One such common field is
35-- names can be overloaded for different types. One such common field is
36-- @#description@. Many components of a Swagger specification can have
36-- @#description@. Many components of a Swagger specification can have
37-- descriptions, and you can use the same name for them:
37-- descriptions, and you can use the same name for them:
38--
38--
39−-- >>> encode $ (mempty :: Response) & #description .~ "No content"
39+-- >>> BSL.putStrLn $ encode $ (mempty :: Response) & #description .~ "No content"
40−-- "{\"description\":\"No content\"}"
40+-- {"description":"No content"}
41-- >>> :{
41-- >>> :{
42−-- encode $ (mempty :: Schema)
42+-- BSL.putStrLn $ encode $ (mempty :: Schema)
43-- & #type ?~ SwaggerBoolean
43-- & #type ?~ SwaggerBoolean
44-- & #description ?~ "To be or not to be"
44-- & #description ?~ "To be or not to be"
45-- :}
45-- :}
46−-- "{\"description\":\"To be or not to be\",\"type\":\"boolean\"}"
46+-- {"description":"To be or not to be","type":"boolean"}
47--
47--
48-- @'ParamSchema'@ is basically the /base schema specification/ and many types
48-- @'ParamSchema'@ is basically the /base schema specification/ and many types
49-- contain it. So for convenience, all @'ParamSchema'@ fields are transitively
49-- contain it. So for convenience, all @'ParamSchema'@ fields are transitively
@@ -51,17 +51,17 @@
51-- access @'SwaggerType'@ of @'Header'@ schema without having to use
51-- access @'SwaggerType'@ of @'Header'@ schema without having to use
52-- @#paramSchema@:
52-- @#paramSchema@:
53--
53--
54−-- >>> encode $ (mempty :: Header) & #type ?~ SwaggerNumber
54+-- >>> BSL.putStrLn $ encode $ (mempty :: Header) & #type ?~ SwaggerNumber
55−-- "{\"type\":\"number\"}"
55+-- {"schema":{"type":"number"}}
56--
56--
57-- Additionally, to simplify working with @'Response'@, both @'Operation'@ and
57-- Additionally, to simplify working with @'Response'@, both @'Operation'@ and
58-- @'Responses'@ have direct access to it via @'Optics.Core.At.at'@. Example:
58-- @'Responses'@ have direct access to it via @'Optics.Core.At.at'@. Example:
59--
59--
60-- >>> :{
60-- >>> :{
61−-- encode $ (mempty :: Operation)
61+-- BSL.putStrLn $ encode $ (mempty :: Operation)
62-- & at 404 ?~ "Not found"
62-- & at 404 ?~ "Not found"
63-- :}
63-- :}
64−-- "{\"responses\":{\"404\":{\"description\":\"Not found\"}}}"
64+-- {"responses":{"404":{"description":"Not found"}}}
65--
65--
66module Data.Swagger.Optics () where
66module Data.Swagger.Optics () where
67
67