1{-# LANGUAGE OverloadedLists #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE QuasiQuotes #-}
5module Data.OpenApiSpec where
13import Data.Aeson.QQ.Simple
14import Data.HashMap.Strict (HashMap)
15import qualified Data.HashSet.InsOrd as InsOrdHS
17import Data.Text (Text)
20import Data.OpenApi.Internal
22import Test.Hspec hiding (example)
26 describe "License Object" $ licenseExample <=> licenseExampleJSON
27 describe "Contact Object" $ contactExample <=> contactExampleJSON
28 describe "Info Object" $ infoExample <=> infoExampleJSON
29 describe "Operation Object" $ operationExample <=> operationExampleJSON
30 describe "Schema Object" $ do
31 context "Primitive Sample" $ schemaPrimitiveExample <=> schemaPrimitiveExampleJSON
32 context "Simple Model" $ schemaSimpleModelExample <=> schemaSimpleModelExampleJSON
33 context "Model with Map/Dictionary Properties" $ schemaModelDictExample <=> schemaModelDictExampleJSON
34 context "Model with Arbitrary Properties" $ schemaAdditionalExample <=> schemaAdditionalExampleJSON
35 context "Model with Example" $ schemaWithExampleExample <=> schemaWithExampleExampleJSON
36 describe "Definitions Object" $ definitionsExample <=> definitionsExampleJSON
37 describe "Parameters Definition Object" $ paramsDefinitionExample <=> paramsDefinitionExampleJSON
38 describe "Responses Definition Object" $ responsesDefinitionExample <=> responsesDefinitionExampleJSON
39 describe "Security Definitions Object" $ securityDefinitionsExample <=> securityDefinitionsExampleJSON
40 describe "OAuth2 Security Definitions with merged Scope" $ oAuth2SecurityDefinitionsExample <=> oAuth2SecurityDefinitionsExampleJSON
41 describe "Composition Schema Example" $ compositionSchemaExample <=> compositionSchemaExampleJSON
42 describe "Swagger Object" $ do
43 context "Example with no paths" $ emptyPathsFieldExample <=> emptyPathsFieldExampleJSON
44 context "Todo Example" $ swaggerExample <=> swaggerExampleJSON
45 context "PetStore Example" $ do
46 it "decodes successfully" $ do
47 fromJSON petstoreExampleJSON `shouldSatisfy` (\x -> case x of Success (_ :: OpenApi) -> True; _ -> False)
48 it "roundtrips: fmap toJSON . fromJSON" $ do
49 (toJSON :: OpenApi -> Value) <$> fromJSON petstoreExampleJSON `shouldBe` Success petstoreExampleJSON
50 testJsonIdempotency (Proxy :: Proxy HttpScheme)
55-- =======================================================================
57-- =======================================================================
61 & title .~ "Swagger Sample App"
62 & description ?~ "This is a sample server Petstore server."
63 & termsOfService ?~ "http://swagger.io/terms/"
64 & contact ?~ contactExample
65 & license ?~ licenseExample
68infoExampleJSON :: Value
69infoExampleJSON = [aesonQQ|
71 "title": "Swagger Sample App",
72 "description": "This is a sample server Petstore server.",
73 "termsOfService": "http://swagger.io/terms/",
75 "name": "API Support",
76 "url": "http://www.swagger.io/support",
77 "email": "support@swagger.io"
81 "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
87-- =======================================================================
89-- =======================================================================
91contactExample :: Contact
92contactExample = mempty
93 & name ?~ "API Support"
94 & url ?~ URL "http://www.swagger.io/support"
95 & email ?~ "support@swagger.io"
97contactExampleJSON :: Value
98contactExampleJSON = [aesonQQ|
100 "name": "API Support",
101 "url": "http://www.swagger.io/support",
102 "email": "support@swagger.io"
106-- =======================================================================
108-- =======================================================================
110licenseExample :: License
111licenseExample = "Apache 2.0"
112 & url ?~ URL "http://www.apache.org/licenses/LICENSE-2.0.html"
114licenseExampleJSON :: Value
115licenseExampleJSON = [aesonQQ|
117 "name": "Apache 2.0",
118 "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
123-- =======================================================================
125-- =======================================================================
127operationExample :: Operation
128operationExample = mempty
129 & tags .~ InsOrdHS.fromList ["pet"]
130 & summary ?~ "Updates a pet in the store with form data"
132 & operationId ?~ "updatePetWithForm"
133 & parameters .~ [Inline (mempty
135 & description ?~ "ID of pet that needs to be updated"
138 & schema ?~ Inline (mempty & type_ ?~ OpenApiString))]
139 & requestBody ?~ Inline (
140 mempty & content . at "application/x-www-form-urlencoded" ?~ (mempty & schema ?~ (Inline (mempty
141 & properties . at "petId" ?~ Inline (mempty
142 & description ?~ "Updated name of the pet"
143 & type_ ?~ OpenApiString)
144 & properties . at "status" ?~ Inline (mempty
145 & description ?~ "Updated status of the pet"
146 & type_ ?~ OpenApiString)))))
147 & at 200 ?~ "Pet updated."
148 & at 405 ?~ "Invalid input"
149 & security .~ [SecurityRequirement [("petstore_auth", ["write:pets", "read:pets"])]]
151operationExampleJSON :: Value
152operationExampleJSON = [aesonQQ|
157 "summary": "Updates a pet in the store with form data",
159 "operationId": "updatePetWithForm",
168 "description": "ID of pet that needs to be updated"
173 "application/x-www-form-urlencoded": {
178 "description": "Updated name of the pet"
182 "description": "Updated status of the pet"
191 "description": "Pet updated."
194 "description": "Invalid input"
208-- =======================================================================
210-- =======================================================================
212schemaPrimitiveExample :: Schema
213schemaPrimitiveExample = mempty
214 & type_ ?~ OpenApiString
217schemaPrimitiveExampleJSON :: Value
218schemaPrimitiveExampleJSON = [aesonQQ|
225schemaSimpleModelExample :: Schema
226schemaSimpleModelExample = mempty
227 & type_ ?~ OpenApiObject
228 & required .~ [ "name" ]
230 [ ("name", Inline (mempty & type_ ?~ OpenApiString))
231 , ("address", Ref (Reference "Address"))
232 , ("age", Inline $ mempty
234 & type_ ?~ OpenApiInteger
235 & format ?~ "int32" ) ]
237schemaSimpleModelExampleJSON :: Value
238schemaSimpleModelExampleJSON = [aesonQQ|
239{ "required": [ "name" ],
245 "$ref": "#/components/schemas/Address"
257schemaModelDictExample :: Schema
258schemaModelDictExample = mempty
259 & type_ ?~ OpenApiObject
260 & additionalProperties ?~ AdditionalPropertiesSchema (Inline (mempty & type_ ?~ OpenApiString))
262schemaModelDictExampleJSON :: Value
263schemaModelDictExampleJSON = [aesonQQ|
266 "additionalProperties": {
272schemaAdditionalExample :: Schema
273schemaAdditionalExample = mempty
274 & type_ ?~ OpenApiObject
275 & additionalProperties ?~ AdditionalPropertiesAllowed True
277schemaAdditionalExampleJSON :: Value
278schemaAdditionalExampleJSON = [aesonQQ|
281 "additionalProperties": true
285schemaWithExampleExample :: Schema
286schemaWithExampleExample = mempty
287 & type_ ?~ OpenApiObject
289 [ ("id", Inline $ mempty
290 & type_ ?~ OpenApiInteger
291 & format ?~ "int64" )
292 , ("name", Inline $ mempty
293 & type_ ?~ OpenApiString) ]
294 & required .~ [ "name" ]
295 & example ?~ [aesonQQ|
302schemaWithExampleExampleJSON :: Value
303schemaWithExampleExampleJSON = [aesonQQ|
325-- =======================================================================
327-- =======================================================================
329definitionsExample :: HashMap Text Schema
331 [ ("Category", mempty
332 & type_ ?~ OpenApiObject
334 [ ("id", Inline $ mempty
335 & type_ ?~ OpenApiInteger
337 , ("name", Inline (mempty & type_ ?~ OpenApiString)) ] )
339 & type_ ?~ OpenApiObject
341 [ ("id", Inline $ mempty
342 & type_ ?~ OpenApiInteger
344 , ("name", Inline (mempty & type_ ?~ OpenApiString)) ] ) ]
346definitionsExampleJSON :: Value
347definitionsExampleJSON = [aesonQQ|
376-- =======================================================================
377-- Parameters Definition object
378-- =======================================================================
380paramsDefinitionExample :: HashMap Text Param
381paramsDefinitionExample =
382 [ ("skipParam", mempty
384 & description ?~ "number of items to skip"
387 & schema ?~ Inline (mempty
388 & type_ ?~ OpenApiInteger
389 & format ?~ "int32" ))
390 , ("limitParam", mempty
392 & description ?~ "max records to return"
395 & schema ?~ Inline (mempty
396 & type_ ?~ OpenApiInteger
397 & format ?~ "int32" )) ]
399paramsDefinitionExampleJSON :: Value
400paramsDefinitionExampleJSON = [aesonQQ|
405 "description": "number of items to skip",
415 "description": "max records to return",
425-- =======================================================================
426-- Responses Definition object
427-- =======================================================================
429responsesDefinitionExample :: HashMap Text Response
430responsesDefinitionExample =
431 [ ("NotFound", mempty & description .~ "Entity not found.")
432 , ("IllegalInput", mempty & description .~ "Illegal input for operation.") ]
434responsesDefinitionExampleJSON :: Value
435responsesDefinitionExampleJSON = [aesonQQ|
438 "description": "Entity not found."
441 "description": "Illegal input for operation."
446-- =======================================================================
447-- Responses Definition object
448-- =======================================================================
450securityDefinitionsExample :: SecurityDefinitions
451securityDefinitionsExample = SecurityDefinitions
452 [ ("api_key", SecurityScheme
453 { _securitySchemeType = SecuritySchemeApiKey (ApiKeyParams "api_key" ApiKeyHeader)
454 , _securitySchemeDescription = Nothing })
455 , ("petstore_auth", SecurityScheme
456 { _securitySchemeType = SecuritySchemeOAuth2 (mempty & implicit ?~ OAuth2Flow
457 { _oAuth2Params = OAuth2ImplicitFlow "http://swagger.io/api/oauth/dialog"
458 , _oAath2RefreshUrl = Nothing
460 [ ("write:pets", "modify pets in your account")
461 , ("read:pets", "read your pets") ] } )
462 , _securitySchemeDescription = Nothing })
463 , ("basic", SecurityScheme
464 { _securitySchemeType = SecuritySchemeHttp Basic
465 , _securitySchemeDescription = Nothing })]
467securityDefinitionsExampleJSON :: Value
468securityDefinitionsExampleJSON = [aesonQQ|
480 "write:pets": "modify pets in your account",
481 "read:pets": "read your pets"
483 "authorizationUrl": "http://swagger.io/api/oauth/dialog"
495oAuth2SecurityDefinitionsReadExample :: SecurityDefinitions
496oAuth2SecurityDefinitionsReadExample = SecurityDefinitions
497 [ ("petstore_auth", SecurityScheme
498 { _securitySchemeType = SecuritySchemeOAuth2 (mempty & implicit ?~ OAuth2Flow
499 { _oAuth2Params = OAuth2ImplicitFlow "http://swagger.io/api/oauth/dialog"
500 , _oAath2RefreshUrl = Nothing
502 [ ("read:pets", "read your pets") ] } )
503 , _securitySchemeDescription = Nothing })
506oAuth2SecurityDefinitionsWriteExample :: SecurityDefinitions
507oAuth2SecurityDefinitionsWriteExample = SecurityDefinitions
508 [ ("petstore_auth", SecurityScheme
509 { _securitySchemeType = SecuritySchemeOAuth2 (mempty & implicit ?~ OAuth2Flow
510 { _oAuth2Params = OAuth2ImplicitFlow "http://swagger.io/api/oauth/dialog"
511 , _oAath2RefreshUrl = Nothing
513 [ ("write:pets", "modify pets in your account") ] } )
514 , _securitySchemeDescription = Nothing })
517oAuth2SecurityDefinitionsExample :: SecurityDefinitions
518oAuth2SecurityDefinitionsExample =
519 oAuth2SecurityDefinitionsWriteExample <>
520 oAuth2SecurityDefinitionsReadExample
522oAuth2SecurityDefinitionsExampleJSON :: Value
523oAuth2SecurityDefinitionsExampleJSON = [aesonQQ|
530 "write:pets": "modify pets in your account",
531 "read:pets": "read your pets"
533 "authorizationUrl": "http://swagger.io/api/oauth/dialog"
540-- =======================================================================
542-- =======================================================================
544emptyPathsFieldExample :: OpenApi
545emptyPathsFieldExample = mempty
547emptyPathsFieldExampleJSON :: Value
548emptyPathsFieldExampleJSON = [aesonQQ|
551 "info": {"version": "", "title": ""},
557swaggerExample :: OpenApi
558swaggerExample = mempty
560 -- & schemes ?~ [Http]
563 & title .~ "Todo API"
565 & license._Just.url ?~ URL "http://mit.com"
566 & description ?~ "This is an API that tests servant-swagger support for a Todo API")
567 & paths.at "/todo/{id}" ?~ (mempty & get ?~ ((mempty :: Operation)
568 & responses . at 200 ?~ Inline (mempty
569 & description .~ "OK"
570 & content . at "application/json" ?~ (mempty
571 & schema ?~ Inline (mempty
572 & type_ ?~ OpenApiObject
573 & example ?~ [aesonQQ|
576 "description": "get milk"
578 & description ?~ "This is some real Todo right here"
580 [ ("created", Inline $ mempty
581 & type_ ?~ OpenApiInteger
583 , ("description", Inline (mempty & type_ ?~ OpenApiString))])))
588 & description ?~ "TodoId param"
590 & schema ?~ Inline (mempty
591 & type_ ?~ OpenApiString ) ]
592 & tags .~ InsOrdHS.fromList [ "todo" ] ))
594swaggerExampleJSON :: Value
595swaggerExampleJSON = [aesonQQ|
602 "url": "http://mit.com",
605 "description": "This is an API that tests servant-swagger support for a Todo API"
621 "description": "TodoId param"
627 "application/json": {
631 "description": "get milk"
634 "description": "This is some real Todo right here",
657petstoreExampleJSON :: Value
658petstoreExampleJSON = [aesonQQ|
663 "title": "Swagger Petstore",
670 "url": "http://petstore.swagger.io/v1"
676 "summary": "List all pets",
677 "operationId": "listPets",
685 "description": "How many items to return at one time (max 100)",
695 "description": "A paged array of pets",
698 "description": "A link to the next page of responses",
705 "application/json": {
732 "description": "unexpected error",
734 "application/json": {
757 "summary": "Create a pet",
758 "operationId": "createPets",
764 "description": "Null response"
767 "description": "unexpected error",
769 "application/json": {
794 "summary": "Info for a specific pet",
795 "operationId": "showPetById",
804 "description": "The id of the pet to retrieve",
812 "description": "Expected response to a valid request",
814 "application/json": {
838 "description": "unexpected error",
840 "application/json": {
928compositionSchemaExample :: Schema
929compositionSchemaExample = mempty
930 & type_ ?~ OpenApiObject
931 & Data.OpenApi.allOf ?~ [
932 Ref (Reference "Other")
934 & type_ ?~ OpenApiObject
936 [ ("greet", Inline $ mempty
937 & type_ ?~ OpenApiString) ])
940compositionSchemaExampleJSON :: Value
941compositionSchemaExampleJSON = [aesonQQ|
946 "$ref": "#/components/schemas/Other"
951 "greet": { "type": "string" }
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list