servant-openapi3 2.0.0.1 → 2.0.1.0
raw patch · 4 files changed
+169/−3 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Servant.OpenApi.Internal: instance (Data.OpenApi.Internal.Schema.ToSchema a, Servant.API.UVerb.HasStatus a, Servant.OpenApi.Internal.AllAccept cs, Servant.OpenApi.Internal.OpenApiMethod method, Servant.OpenApi.Internal.HasOpenApi (Servant.API.UVerb.UVerb method cs as)) => Servant.OpenApi.Internal.HasOpenApi (Servant.API.UVerb.UVerb method cs (a : as))
+ Servant.OpenApi.Internal: instance Data.OpenApi.Internal.Schema.ToSchema a => Data.OpenApi.Internal.Schema.ToSchema (Servant.API.UVerb.WithStatus s a)
+ Servant.OpenApi.Internal: instance Servant.OpenApi.Internal.HasOpenApi (Servant.API.UVerb.UVerb method cs '[])
Files
- example/example.cabal +2/−1
- servant-openapi3.cabal +3/−2
- src/Servant/OpenApi/Internal.hs +55/−0
- test/Servant/OpenApiSpec.hs +109/−0
example/example.cabal view
@@ -16,7 +16,8 @@ tested-with: GHC ==8.4.4 || ==8.6.5- || ==8.8.3+ || ==8.8.4+ || ==8.10.2 library ghc-options: -Wall
servant-openapi3.cabal view
@@ -1,5 +1,5 @@ name: servant-openapi3-version: 2.0.0.1+version: 2.0.1.0 synopsis: Generate a Swagger/OpenAPI/OAS 3.0 specification for your servant API. description: Swagger is a project used to describe and document RESTful APIs. The core of the @@ -31,7 +31,8 @@ tested-with: GHC ==8.4.4 || ==8.6.5- || ==8.8.3+ || ==8.8.4+ || ==8.10.2 extra-source-files: README.md
src/Servant/OpenApi/Internal.hs view
@@ -11,11 +11,15 @@ #if __GLASGOW_HASKELL__ >= 806 {-# LANGUAGE UndecidableInstances #-} #endif+{-# OPTIONS_GHC -Wno-orphans #-} module Servant.OpenApi.Internal where import Prelude () import Prelude.Compat +#if MIN_VERSION_servant(0,18,1)+import Control.Applicative ((<|>))+#endif import Control.Lens import Data.Aeson import Data.Foldable (toList)@@ -182,6 +186,57 @@ instance OpenApiMethod 'OPTIONS where openApiMethod _ = options instance OpenApiMethod 'HEAD where openApiMethod _ = head_ instance OpenApiMethod 'PATCH where openApiMethod _ = patch++#if MIN_VERSION_servant(0,18,1)+instance HasOpenApi (UVerb method cs '[]) where+ toOpenApi _ = mempty++-- | @since <2.0.1.0>+instance+ {-# OVERLAPPABLE #-}+ ( ToSchema a,+ HasStatus a,+ AllAccept cs,+ OpenApiMethod method,+ HasOpenApi (UVerb method cs as)+ ) =>+ HasOpenApi (UVerb method cs (a ': as))+ where+ toOpenApi _ =+ toOpenApi (Proxy :: Proxy (Verb method (StatusOf a) cs a))+ `combineSwagger` toOpenApi (Proxy :: Proxy (UVerb method cs as))+ where+ -- workaround for https://github.com/GetShopTV/swagger2/issues/218+ combinePathItem :: PathItem -> PathItem -> PathItem+ combinePathItem s t = PathItem+ { _pathItemGet = _pathItemGet s <> _pathItemGet t+ , _pathItemPut = _pathItemPut s <> _pathItemPut t+ , _pathItemPost = _pathItemPost s <> _pathItemPost t+ , _pathItemDelete = _pathItemDelete s <> _pathItemDelete t+ , _pathItemOptions = _pathItemOptions s <> _pathItemOptions t+ , _pathItemHead = _pathItemHead s <> _pathItemHead t+ , _pathItemPatch = _pathItemPatch s <> _pathItemPatch t+ , _pathItemTrace = _pathItemTrace s <> _pathItemTrace t+ , _pathItemParameters = _pathItemParameters s <> _pathItemParameters t+ , _pathItemSummary = _pathItemSummary s <|> _pathItemSummary t+ , _pathItemDescription = _pathItemDescription s <|> _pathItemDescription t+ , _pathItemServers = _pathItemServers s <> _pathItemServers t+ }++ combineSwagger :: OpenApi -> OpenApi -> OpenApi+ combineSwagger s t = OpenApi+ { _openApiInfo = _openApiInfo s <> _openApiInfo t+ , _openApiServers = _openApiServers s <> _openApiServers t+ , _openApiPaths = InsOrdHashMap.unionWith combinePathItem (_openApiPaths s) (_openApiPaths t)+ , _openApiComponents = _openApiComponents s <> _openApiComponents t+ , _openApiSecurity = _openApiSecurity s <> _openApiSecurity t+ , _openApiTags = _openApiTags s <> _openApiTags t+ , _openApiExternalDocs = _openApiExternalDocs s <|> _openApiExternalDocs t+ }++instance ToSchema a => ToSchema (WithStatus s a) where+ declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)+#endif instance {-# OVERLAPPABLE #-} (ToSchema a, AllAccept cs, KnownNat status, OpenApiMethod method) => HasOpenApi (Verb method status cs a) where toOpenApi _ = toOpenApi (Proxy :: Proxy (Verb method status cs (Headers '[] a)))
test/Servant/OpenApiSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-}@@ -5,6 +6,9 @@ {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE PackageImports #-}+#if MIN_VERSION_servant(0,18,1)+{-# LANGUAGE TypeFamilies #-}+#endif module Servant.OpenApiSpec where import Control.Lens@@ -37,6 +41,9 @@ it "Comprehensive API" $ do let _x = toOpenApi comprehensiveAPI True `shouldBe` True -- type-level test+#if MIN_VERSION_servant(0,18,1)+ it "UVerb API" $ checkOpenApi uverbOpenApi uverbAPI+#endif main :: IO () main = hspec spec@@ -418,3 +425,105 @@ } |] +-- =======================================================================+-- UVerb API+-- =======================================================================++#if MIN_VERSION_servant(0,18,1)++data FisxUser = FisxUser {name :: String}+ deriving (Eq, Show, Generic)++instance ToSchema FisxUser++instance HasStatus FisxUser where+ type StatusOf FisxUser = 203++data ArianUser = ArianUser+ deriving (Eq, Show, Generic)++instance ToSchema ArianUser++type UVerbAPI = "fisx" :> UVerb 'GET '[JSON] '[FisxUser, WithStatus 303 String]+ :<|> "arian" :> UVerb 'POST '[JSON] '[WithStatus 201 ArianUser]++uverbOpenApi :: OpenApi+uverbOpenApi = toOpenApi (Proxy :: Proxy UVerbAPI)++uverbAPI :: Value+uverbAPI = [aesonQQ|+{+ "openapi": "3.0.0",+ "info": {+ "version": "",+ "title": ""+ },+ "components": {+ "schemas": {+ "ArianUser": {+ "type": "string",+ "enum": [+ "ArianUser"+ ]+ },+ "FisxUser": {+ "required": [+ "name"+ ],+ "type": "object",+ "properties": {+ "name": {+ "type": "string"+ }+ }+ }+ }+ },+ "paths": {+ "/arian": {+ "post": {+ "responses": {+ "201": {+ "content": {+ "application/json;charset=utf-8": {+ "schema": {+ "$ref": "#/components/schemas/ArianUser"+ }+ }+ },+ "description": ""+ }+ }+ }+ },+ "/fisx": {+ "get": {+ "responses": {+ "303": {+ "content": {+ "application/json;charset=utf-8": {+ "schema": {+ "type": "string"+ }+ }+ },+ "description": ""+ },+ "203": {+ "content": {+ "application/json;charset=utf-8": {+ "schema": {+ "$ref": "#/components/schemas/FisxUser"+ }+ }+ },+ "description": ""+ }+ }+ }+ }+ }+}+|]++#endif