Commit a72bf92a authored by Alfredo Di Napoli's avatar Alfredo Di Napoli

Merge branch 'adinapoli/restore-swagger-auth' into 'dev'

Switch to OpenAPI3 from Swagger2, to use proper Bearer token

Closes #427

See merge request !369
parents a3879ca5 7decc3f4
Pipeline #7099 passed with stages
in 52 minutes and 4 seconds
...@@ -467,6 +467,8 @@ library ...@@ -467,6 +467,8 @@ library
Gargantext.Database.Schema.NodeNode Gargantext.Database.Schema.NodeNode
Gargantext.Database.Schema.Prelude Gargantext.Database.Schema.Prelude
Gargantext.Database.Types Gargantext.Database.Types
Gargantext.Orphans
Gargantext.Orphans.OpenAPI
Gargantext.Utils.Aeson Gargantext.Utils.Aeson
Gargantext.Utils.Servant Gargantext.Utils.Servant
Gargantext.Utils.UTCTime Gargantext.Utils.UTCTime
...@@ -562,6 +564,7 @@ library ...@@ -562,6 +564,7 @@ library
, opaleye ^>= 0.9.6.1 , opaleye ^>= 0.9.6.1
, opaleye-textsearch >= 0.2.0.0 , opaleye-textsearch >= 0.2.0.0
, openalex , openalex
, openapi3 >= 3.2.3
, parallel ^>= 3.2.2.0 , parallel ^>= 3.2.2.0
, parsec ^>= 3.1.16.1 , parsec ^>= 3.1.16.1
, patches-class ^>= 0.1.0.1 , patches-class ^>= 0.1.0.1
...@@ -588,6 +591,7 @@ library ...@@ -588,6 +591,7 @@ library
, servant-client-core >= 0.20 && < 0.21 , servant-client-core >= 0.20 && < 0.21
, servant-ekg ^>= 0.3.1 , servant-ekg ^>= 0.3.1
, servant-routes < 0.2 , servant-routes < 0.2
, servant-openapi3 >= 2.0.1.6
, servant-server >= 0.18.3 && < 0.21 , servant-server >= 0.18.3 && < 0.21
, servant-swagger ^>= 1.2 , servant-swagger ^>= 1.2
, servant-swagger-ui ^>= 0.3.5.3.5.0 , servant-swagger-ui ^>= 0.3.5.3.5.0
......
...@@ -64,6 +64,7 @@ import Servant (HasServer(..), ServerT) ...@@ -64,6 +64,7 @@ import Servant (HasServer(..), ServerT)
import Servant.Server.Internal.Delayed (addParameterCheck) import Servant.Server.Internal.Delayed (addParameterCheck)
import Servant.Server.Internal.DelayedIO (DelayedIO(..)) import Servant.Server.Internal.DelayedIO (DelayedIO(..))
import Servant.Swagger qualified as Swagger import Servant.Swagger qualified as Swagger
import Servant.OpenApi qualified as OpenAPI
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Types -- Types
...@@ -299,6 +300,9 @@ instance AddSetCookies ('S n) old new => AddSetCookies ('S n) (AccessPolicyManag ...@@ -299,6 +300,9 @@ instance AddSetCookies ('S n) old new => AddSetCookies ('S n) (AccessPolicyManag
instance Swagger.HasSwagger sub => Swagger.HasSwagger (PolicyChecked sub) where instance Swagger.HasSwagger sub => Swagger.HasSwagger (PolicyChecked sub) where
toSwagger _ = Swagger.toSwagger (Proxy :: Proxy sub) toSwagger _ = Swagger.toSwagger (Proxy :: Proxy sub)
instance OpenAPI.HasOpenApi sub => OpenAPI.HasOpenApi (PolicyChecked sub) where
toOpenApi _ = OpenAPI.toOpenApi (Proxy :: Proxy sub)
instance HasEndpoint sub => HasEndpoint (PolicyChecked sub) where instance HasEndpoint sub => HasEndpoint (PolicyChecked sub) where
getEndpoint _ = getEndpoint (Proxy :: Proxy sub) getEndpoint _ = getEndpoint (Proxy :: Proxy sub)
enumerateEndpoints _ = enumerateEndpoints (Proxy :: Proxy sub) enumerateEndpoints _ = enumerateEndpoints (Proxy :: Proxy sub)
......
...@@ -15,6 +15,7 @@ module Gargantext.API.Routes.Named ( ...@@ -15,6 +15,7 @@ module Gargantext.API.Routes.Named (
, ForgotPasswordAPI(..) , ForgotPasswordAPI(..)
, ForgotPasswordAsyncAPI(..) , ForgotPasswordAsyncAPI(..)
, GargVersion(..) , GargVersion(..)
, module Gargantext.API.Routes.Named.Private
) where ) where
import Data.Text (Text) import Data.Text (Text)
...@@ -74,10 +75,9 @@ data GargAPI' mode = GargAPI' ...@@ -74,10 +75,9 @@ data GargAPI' mode = GargAPI'
, gargForgotPasswordAsyncAPI :: mode :- "async" :> "forgot-password" :> NamedRoutes ForgotPasswordAsyncAPI , gargForgotPasswordAsyncAPI :: mode :- "async" :> "forgot-password" :> NamedRoutes ForgotPasswordAsyncAPI
, gargVersionAPI :: mode :- NamedRoutes GargVersion , gargVersionAPI :: mode :- NamedRoutes GargVersion
, gargPrivateAPI :: mode :- NamedRoutes GargPrivateAPI , gargPrivateAPI :: mode :- NamedRoutes GargPrivateAPI
, gargPublicAPI :: mode :- "public" :> NamedRoutes GargPublicAPI , gargPublicAPI :: mode :- NamedRoutes GargPublicAPI
} deriving Generic } deriving Generic
newtype AuthAPI mode = AuthAPI newtype AuthAPI mode = AuthAPI
{ authEp :: mode :- "auth" :> Summary "AUTH API" { authEp :: mode :- "auth" :> Summary "AUTH API"
:> ReqBody '[JSON] AuthRequest :> ReqBody '[JSON] AuthRequest
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
module Gargantext.API.Routes.Named.Public ( module Gargantext.API.Routes.Named.Public (
-- * Routes types -- * Routes types
GargPublicAPI(..) GargPublicAPI'(..)
, GargPublicAPI(..)
, HomeAPI(..) , HomeAPI(..)
, NodeAPI(..) , NodeAPI(..)
) where ) where
...@@ -13,8 +14,11 @@ import Gargantext.API.Routes.Named.File (FileAPI) ...@@ -13,8 +14,11 @@ import Gargantext.API.Routes.Named.File (FileAPI)
import Gargantext.Database.Admin.Types.Node ( NodeId ) import Gargantext.Database.Admin.Types.Node ( NodeId )
import Servant.API import Servant.API
newtype GargPublicAPI mode = GargPublicAPI
{ gargAPIVersion :: mode :- "public" :> NamedRoutes GargPublicAPI'
} deriving Generic
data GargPublicAPI mode = GargPublicAPI data GargPublicAPI' mode = GargPublicAPI'
{ publicHomeAPI :: mode :- NamedRoutes HomeAPI { publicHomeAPI :: mode :- NamedRoutes HomeAPI
, publicNodeAPI :: mode :- NamedRoutes NodeAPI , publicNodeAPI :: mode :- NamedRoutes NodeAPI
} deriving Generic } deriving Generic
......
...@@ -29,7 +29,7 @@ import Servant ...@@ -29,7 +29,7 @@ import Servant
-- would fail because '#/share/NodeCorpus/16' by the RFC3968 spec is considered -- would fail because '#/share/NodeCorpus/16' by the RFC3968 spec is considered
-- an uriFragment, but BaseUrl cannot handle that. -- an uriFragment, but BaseUrl cannot handle that.
newtype ShareLink = ShareLink { getShareLink :: URI } newtype ShareLink = ShareLink { getShareLink :: URI }
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord, Generic)
renderShareLink :: ShareLink -> T.Text renderShareLink :: ShareLink -> T.Text
renderShareLink = T.pack . show . getShareLink renderShareLink = T.pack . show . getShareLink
......
...@@ -20,7 +20,7 @@ import Gargantext.API.GraphQL as GraphQL ...@@ -20,7 +20,7 @@ import Gargantext.API.GraphQL as GraphQL
import Gargantext.API.Prelude (GargM) import Gargantext.API.Prelude (GargM)
import Gargantext.API.Routes.Named import Gargantext.API.Routes.Named
import Gargantext.API.Server.Named.Public (serverPublicGargAPI) import Gargantext.API.Server.Named.Public (serverPublicGargAPI)
import Gargantext.API.Swagger (swaggerDoc) import Gargantext.API.Swagger (openApiDoc)
import Gargantext.API.ThrowAll (serverPrivateGargAPI) import Gargantext.API.ThrowAll (serverPrivateGargAPI)
import Gargantext.Core.Notifications.Dispatcher.WebSocket qualified as Dispatcher import Gargantext.Core.Notifications.Dispatcher.WebSocket qualified as Dispatcher
import Gargantext.Core.Config (gc_frontend_config, hasConfig) import Gargantext.Core.Config (gc_frontend_config, hasConfig)
...@@ -50,7 +50,7 @@ serverGargAPI env ...@@ -50,7 +50,7 @@ serverGargAPI env
server :: Env -> API AsServer server :: Env -> API AsServer
server env = server env =
API $ \errScheme -> NamedAPI API $ \errScheme -> NamedAPI
{ swaggerAPI = swaggerSchemaUIServer swaggerDoc { swaggerAPI = swaggerSchemaUIServer openApiDoc
, backendAPI = hoistServerWithContext , backendAPI = hoistServerWithContext
(Proxy :: Proxy (NamedRoutes BackEndAPI)) (Proxy :: Proxy (NamedRoutes BackEndAPI))
(Proxy :: Proxy AuthContext) (Proxy :: Proxy AuthContext)
......
...@@ -26,8 +26,8 @@ import Servant ...@@ -26,8 +26,8 @@ import Servant
import Servant.Server.Generic (AsServerT) import Servant.Server.Generic (AsServerT)
serverPublicGargAPI :: IsGargServer env err m => Text -> Named.GargPublicAPI (AsServerT m) serverPublicGargAPI :: IsGargServer env err m => Text -> Named.GargPublicAPI (AsServerT m)
serverPublicGargAPI baseUrl = serverPublicGargAPI baseUrl = Named.GargPublicAPI $
Named.GargPublicAPI Named.GargPublicAPI'
{ publicHomeAPI = api_home baseUrl { publicHomeAPI = api_home baseUrl
, publicNodeAPI = Named.NodeAPI api_node , publicNodeAPI = Named.NodeAPI api_node
} }
......
{-# OPTIONS_GHC -freduction-depth=400 #-} {-# OPTIONS_GHC -freduction-depth=400 #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-| {-|
Module : Gargantext.API.Swagger Module : Gargantext.API.Swagger
...@@ -12,30 +14,45 @@ Portability : POSIX ...@@ -12,30 +14,45 @@ Portability : POSIX
-} -}
--------------------------------------------------------------------- ---------------------------------------------------------------------
module Gargantext.API.Swagger where module Gargantext.API.Swagger (
--------------------------------------------------------------------- backendApiProxy
, openApiDoc
) where
import Control.Lens ((?~)) import Control.Lens ((?~))
import Data.Swagger import Data.OpenApi
import Data.Version (showVersion) import Data.Version (showVersion)
import Gargantext.API.Routes.Named.Public qualified as Named
import Gargantext.API.Routes.Named qualified as Named import Gargantext.API.Routes.Named qualified as Named
import Gargantext.Orphans () -- instance HasOpenApi
import Gargantext.Prelude import Gargantext.Prelude
import Paths_gargantext qualified as PG -- cabal magic build module import Paths_gargantext qualified as PG -- cabal magic build module
import Servant import Servant
import Servant.Swagger (toSwagger, subOperations) import Servant.OpenApi
backendApiProxy :: Proxy (ToServantApi Named.BackEndAPI) backendApiProxy :: Proxy (NamedRoutes (Named.MkBackEndAPI (Named.GargAPIVersion Named.GargAPI')))
backendApiProxy = Proxy backendApiProxy = Proxy
-- | Swagger Specifications privateOps :: Proxy (NamedRoutes (Named.MkBackEndAPI (Named.GargAPIVersion Named.GargPrivateAPI)))
swaggerDoc :: Swagger privateOps = Proxy
swaggerDoc = toSwagger backendApiProxy
publicOps :: Proxy (NamedRoutes (Named.MkBackEndAPI (Named.GargAPIVersion Named.GargPublicAPI)))
publicOps = Proxy
-- | OpenAPI Specification. It supports programmatically adding the `Bearer` to the `Authorization`
-- header, which makes the Swagger UI actually useable, unlike the 'swaggerDoc' counterpart which
-- is stuck on version 2.x of the OpenAPI spec.
openApiDoc :: OpenApi
openApiDoc = toOpenApi backendApiProxy
& info.title .~ "GarganText" & info.title .~ "GarganText"
& info.version .~ (cs $ showVersion PG.version) & info.version .~ (cs $ showVersion PG.version)
-- & info.base_url ?~ (URL "http://gargantext.org/")
& info.description ?~ "REST API specifications" & info.description ?~ "REST API specifications"
-- & tags .~ Set.fromList [Tag "Garg" (Just "Main perations") Nothing]
& applyTagsFor (subOperations backendApiProxy backendApiProxy) & applyTagsFor (subOperations backendApiProxy backendApiProxy)
["Gargantext" & description ?~ "Main operations"] ["Gargantext" & description ?~ "All operations"]
& applyTagsFor (subOperations privateOps backendApiProxy)
["Private operations" & description ?~ "Operations requiring authentications"]
& applyTagsFor (subOperations publicOps backendApiProxy)
["Public operations" & description ?~ "Operations which don't require a valid authentication"]
& info.license ?~ ("AGPLV3 (English) and CECILL (French)" & url ?~ URL urlLicence ) & info.license ?~ ("AGPLV3 (English) and CECILL (French)" & url ?~ URL urlLicence )
where where
urlLicence = "https://gitlab.iscpif.fr/gargantext/haskell-gargantext/blob/master/LICENSE" urlLicence = "https://gitlab.iscpif.fr/gargantext/haskell-gargantext/blob/master/LICENSE"
module Gargantext.Orphans (
module Gargantext.Orphans.OpenAPI
) where
import Gargantext.Orphans.OpenAPI
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE LambdaCase #-}
module Gargantext.Orphans.OpenAPI where
import Control.Lens
import Data.HashMap.Strict.InsOrd qualified as HM
import Data.OpenApi as OpenAPI hiding (Header, Server)
import Data.OpenApi.Declare
import Data.Swagger.Internal qualified as Swagger
import Data.Swagger qualified as Swagger
import Data.Text qualified as T
import Data.Typeable
import Prelude
import qualified Data.Swagger.Declare as SwaggerDeclare
import Servant.API
import Servant.Auth
import Servant.OpenApi
-- Auth instances
instance (HasOpenApi api) => HasOpenApi (Servant.Auth.Auth '[] a :> api) where
toOpenApi Proxy = toOpenApi $ Proxy @api
instance (HasOpenApi (Servant.Auth.Auth auths a :> api)) => HasOpenApi (Servant.Auth.Auth (Servant.Auth.BasicAuth : auths) a :> api) where
toOpenApi Proxy = addSecurity $ toOpenApi $ Proxy @(Servant.Auth.Auth auths a :> api)
where
addSecurity = addSecurityRequirement identifier . addSecurityScheme identifier securityScheme
identifier :: T.Text = "BasicAuth"
securityScheme =
SecurityScheme
{ _securitySchemeType = SecuritySchemeHttp HttpSchemeBasic
, _securitySchemeDescription = Just "Basic Authentication"
}
instance (HasOpenApi (Servant.Auth.Auth auths a :> api)) => HasOpenApi (Servant.Auth.Auth (Servant.Auth.JWT : auths) a :> api) where
toOpenApi Proxy = addSecurity $ toOpenApi $ Proxy @(Servant.Auth.Auth auths a :> api)
where
addSecurity = addSecurityRequirement identifier . addSecurityScheme identifier securityScheme
identifier :: T.Text = "JWT"
securityScheme =
SecurityScheme
{ _securitySchemeType = SecuritySchemeHttp $ HttpSchemeBearer $ Just "JWT"
, _securitySchemeDescription = Just "Bearer Authentication"
}
instance (HasOpenApi (Servant.Auth.Auth auths a :> api)) => HasOpenApi (Servant.Auth.Auth (Servant.Auth.Cookie : auths) a :> api) where
toOpenApi Proxy = addSecurity $ toOpenApi $ Proxy @(Servant.Auth.Auth auths a :> api)
where
addSecurity = addSecurityRequirement identifier . addSecurityScheme identifier securityScheme
identifier :: T.Text = "Cookie"
securityScheme =
SecurityScheme
{ _securitySchemeType = SecuritySchemeHttp $ HttpSchemeBearer $ Just "JWT"
, _securitySchemeDescription = Just "Cookie Authentication"
}
addSecurityScheme :: T.Text -> SecurityScheme -> OpenApi -> OpenApi
addSecurityScheme securityIdentifier securityScheme openApi =
openApi
{ _openApiComponents =
(_openApiComponents openApi)
{ _componentsSecuritySchemes =
_componentsSecuritySchemes (_openApiComponents openApi)
<> SecurityDefinitions (HM.singleton securityIdentifier securityScheme)
}
}
addSecurityRequirement :: T.Text -> OpenApi -> OpenApi
addSecurityRequirement securityRequirement =
allOperations
. security
%~ ((SecurityRequirement $ HM.singleton securityRequirement []) :)
-- Working with the compat shim a bit more pleasant
class SwaggerConvertible a b where
swagConv :: Iso' a b
--
-- Instances
--
instance SwaggerConvertible OpenAPI.Discriminator T.Text where
swagConv = iso OpenAPI._discriminatorPropertyName convertDiscriminator
where
convertDiscriminator :: T.Text -> OpenAPI.Discriminator
convertDiscriminator t = OpenAPI.Discriminator t mempty
instance SwaggerConvertible OpenAPI.OpenApiType (Swagger.SwaggerType 'Swagger.SwaggerKindSchema) where
swagConv = iso fromOpenAPI toOpenAPI
where
toOpenAPI :: Swagger.SwaggerType t -> OpenAPI.OpenApiType
toOpenAPI Swagger.SwaggerString = OpenAPI.OpenApiString
toOpenAPI Swagger.SwaggerNumber = OpenAPI.OpenApiNumber
toOpenAPI Swagger.SwaggerInteger = OpenAPI.OpenApiInteger
toOpenAPI Swagger.SwaggerBoolean = OpenAPI.OpenApiBoolean
toOpenAPI Swagger.SwaggerArray = OpenAPI.OpenApiArray
toOpenAPI Swagger.SwaggerFile = OpenAPI.OpenApiString -- OpenAPI lacks file type, fallback to string
toOpenAPI Swagger.SwaggerNull = OpenAPI.OpenApiNull
toOpenAPI Swagger.SwaggerObject = OpenAPI.OpenApiObject
fromOpenAPI OpenAPI.OpenApiString = Swagger.SwaggerString
fromOpenAPI OpenAPI.OpenApiNumber = Swagger.SwaggerNumber
fromOpenAPI OpenAPI.OpenApiInteger = Swagger.SwaggerInteger
fromOpenAPI OpenAPI.OpenApiBoolean = Swagger.SwaggerBoolean
fromOpenAPI OpenAPI.OpenApiArray = Swagger.SwaggerArray
fromOpenAPI OpenAPI.OpenApiNull = Swagger.SwaggerNull
fromOpenAPI OpenAPI.OpenApiObject = Swagger.SwaggerObject
instance SwaggerConvertible OpenAPI.Xml (Swagger.Xml) where
swagConv = iso fromOpenAPI toOpenAPI
where
fromOpenAPI :: Xml -> Swagger.Xml
fromOpenAPI OpenAPI.Xml
{ OpenAPI._xmlName = xname
, OpenAPI._xmlNamespace = xnamespace
, OpenAPI._xmlPrefix = xprefix
, OpenAPI._xmlAttribute = xattribute
, OpenAPI._xmlWrapped = xwrapped
} = Swagger.Xml { Swagger._xmlName = xname
, Swagger._xmlNamespace = xnamespace
, Swagger._xmlPrefix = xprefix
, Swagger._xmlAttribute = xattribute
, Swagger._xmlWrapped = xwrapped }
toOpenAPI :: Swagger.Xml -> Xml
toOpenAPI Swagger.Xml { Swagger._xmlName = xname
, Swagger._xmlNamespace = xnamespace
, Swagger._xmlPrefix = xprefix
, Swagger._xmlAttribute = xattribute
, Swagger._xmlWrapped = xwrapped } =
OpenAPI.Xml
{ OpenAPI._xmlName = xname
, OpenAPI._xmlNamespace = xnamespace
, OpenAPI._xmlPrefix = xprefix
, OpenAPI._xmlAttribute = xattribute
, OpenAPI._xmlWrapped = xwrapped
}
instance SwaggerConvertible OpenAPI.URL (Swagger.URL) where
swagConv = iso fromOpenAPI toOpenAPI
where
fromOpenAPI :: URL -> Swagger.URL
fromOpenAPI (URL u) = Swagger.URL u
toOpenAPI :: Swagger.URL -> URL
toOpenAPI = OpenAPI.URL . Swagger.getUrl
instance SwaggerConvertible ExternalDocs Swagger.ExternalDocs where
swagConv = iso fromOpenAPI toOpenAPI
where
toOpenAPI :: Swagger.ExternalDocs -> ExternalDocs
toOpenAPI Swagger.ExternalDocs { Swagger._externalDocsDescription = desc
, Swagger._externalDocsUrl = docurl } =
OpenAPI.ExternalDocs
{ OpenAPI._externalDocsDescription = desc
, OpenAPI._externalDocsUrl = view (from swagConv) $ docurl
}
fromOpenAPI :: ExternalDocs -> Swagger.ExternalDocs
fromOpenAPI OpenAPI.ExternalDocs
{ OpenAPI._externalDocsDescription = desc
, OpenAPI._externalDocsUrl = docurl
} = Swagger.ExternalDocs { Swagger._externalDocsDescription = desc
, Swagger._externalDocsUrl = view swagConv docurl
}
instance SwaggerConvertible a b => SwaggerConvertible (Referenced a) (Swagger.Referenced b) where
swagConv = iso fromOpenAPI toOpenAPI
where
fromOpenAPI :: Referenced a -> Swagger.Referenced b
fromOpenAPI (OpenAPI.Ref (OpenAPI.Reference ref)) = Swagger.Ref (Swagger.Reference ref)
fromOpenAPI (OpenAPI.Inline s) = Swagger.Inline (view swagConv s)
toOpenAPI :: Swagger.Referenced b -> OpenAPI.Referenced a
toOpenAPI (Swagger.Ref ref) = OpenAPI.Ref $ OpenAPI.Reference (Swagger.getReference ref)
toOpenAPI (Swagger.Inline s) = OpenAPI.Inline $ view (from swagConv) s
instance SwaggerConvertible Schema Swagger.Schema where
swagConv = iso toSwaggerSchema fromSwaggerSchema
instance SwaggerConvertible AdditionalProperties Swagger.AdditionalProperties where
swagConv = iso fromOpenAPI toOpenAPI
where
fromOpenAPI :: AdditionalProperties -> Swagger.AdditionalProperties
fromOpenAPI (OpenAPI.AdditionalPropertiesAllowed allowed) =
Swagger.AdditionalPropertiesAllowed allowed
fromOpenAPI (OpenAPI.AdditionalPropertiesSchema ref) =
Swagger.AdditionalPropertiesSchema (view swagConv ref)
toOpenAPI :: Swagger.AdditionalProperties -> AdditionalProperties
toOpenAPI (Swagger.AdditionalPropertiesAllowed allowed) =
OpenAPI.AdditionalPropertiesAllowed allowed
toOpenAPI (Swagger.AdditionalPropertiesSchema ref) =
OpenAPI.AdditionalPropertiesSchema (view (from swagConv) ref)
--
-- Putting everything together
--
fromParamSchema :: Swagger.ParamSchema 'Swagger.SwaggerKindSchema -> Schema
fromParamSchema ps = OpenAPI.Schema
{ OpenAPI._schemaTitle = Nothing
, OpenAPI._schemaDescription = Nothing
, OpenAPI._schemaDefault = view Swagger.default_ ps
, OpenAPI._schemaExample = Nothing
, OpenAPI._schemaType = view (from swagConv) <$> view Swagger.type_ ps
, OpenAPI._schemaFormat = view Swagger.format ps
, OpenAPI._schemaNullable = Nothing
, OpenAPI._schemaEnum = view Swagger.enum_ ps
, OpenAPI._schemaMaximum = view Swagger.maximum_ ps
, OpenAPI._schemaExclusiveMaximum = Swagger._paramSchemaExclusiveMaximum ps
, OpenAPI._schemaMinimum = Swagger._paramSchemaMinimum ps
, OpenAPI._schemaExclusiveMinimum = Swagger._paramSchemaExclusiveMinimum ps
, OpenAPI._schemaMaxLength = Swagger._paramSchemaMaxLength ps
, OpenAPI._schemaMinLength = Swagger._paramSchemaMinLength ps
, OpenAPI._schemaPattern = Swagger._paramSchemaPattern ps
, OpenAPI._schemaMaxItems = Swagger._paramSchemaMaxItems ps
, OpenAPI._schemaMinItems = Swagger._paramSchemaMinItems ps
, OpenAPI._schemaUniqueItems = view Swagger.uniqueItems ps
, OpenAPI._schemaMaxProperties = Nothing
, OpenAPI._schemaMinProperties = Nothing
, OpenAPI._schemaAdditionalProperties = Nothing
, OpenAPI._schemaItems = convertItems <$> view Swagger.items ps
, OpenAPI._schemaProperties = mempty
, OpenAPI._schemaRequired = mempty
, OpenAPI._schemaAllOf = Nothing
, OpenAPI._schemaOneOf = Nothing
, OpenAPI._schemaNot = Nothing
, OpenAPI._schemaAnyOf = Nothing
, OpenAPI._schemaDiscriminator = Nothing
, OpenAPI._schemaReadOnly = Nothing
, OpenAPI._schemaWriteOnly = Nothing
, OpenAPI._schemaXml = Nothing
, OpenAPI._schemaExternalDocs = Nothing
, OpenAPI._schemaDeprecated = Nothing
, OpenAPI._schemaMultipleOf = view Swagger.multipleOf ps
}
convertItems :: Swagger.SwaggerItems 'Swagger.SwaggerKindSchema -> OpenAPI.OpenApiItems
convertItems (Swagger.SwaggerItemsPrimitive _collectionFormat paramSchema) =
OpenAPI.OpenApiItemsObject $ OpenAPI.Inline $ fromParamSchema paramSchema
convertItems (Swagger.SwaggerItemsObject referencedSchema) =
OpenAPI.OpenApiItemsObject $ view (from swagConv) $ referencedSchema
convertItems (Swagger.SwaggerItemsArray referencedSchemas) =
OpenAPI.OpenApiItemsArray $ map (view (from swagConv)) $ referencedSchemas
convertItems' :: OpenApiItems -> Swagger.SwaggerItems 'Swagger.SwaggerKindSchema
convertItems' = \case
OpenAPI.OpenApiItemsObject s -> Swagger.SwaggerItemsObject (view swagConv s)
OpenAPI.OpenApiItemsArray xs -> Swagger.SwaggerItemsArray $ map (view swagConv) xs
fromSwaggerSchema :: Swagger.Schema -> OpenAPI.Schema
fromSwaggerSchema swaggerSchema = OpenAPI.Schema
{ OpenAPI._schemaTitle = view Swagger.title swaggerSchema
, OpenAPI._schemaDescription = view Swagger.description swaggerSchema
, OpenAPI._schemaDefault = view Swagger.default_ swaggerSchema
, OpenAPI._schemaExample = view Swagger.example swaggerSchema
, OpenAPI._schemaType = view (from swagConv) <$> view Swagger.type_ swaggerSchema
, OpenAPI._schemaFormat = view Swagger.format swaggerSchema
, OpenAPI._schemaNullable = Nothing
, OpenAPI._schemaEnum = view Swagger.enum_ swaggerSchema
, OpenAPI._schemaMaximum = view Swagger.maximum_ swaggerSchema
, OpenAPI._schemaExclusiveMaximum = swaggerSchema ^. Swagger.paramSchema . Swagger.exclusiveMaximum
, OpenAPI._schemaMinimum = view Swagger.minimum_ swaggerSchema
, OpenAPI._schemaExclusiveMinimum = swaggerSchema ^. Swagger.paramSchema . Swagger.exclusiveMinimum
, OpenAPI._schemaMaxLength = swaggerSchema ^. Swagger.paramSchema . Swagger.maxLength
, OpenAPI._schemaMinLength = swaggerSchema ^. Swagger.paramSchema . Swagger.minLength
, OpenAPI._schemaPattern = swaggerSchema ^. Swagger.paramSchema . Swagger.pattern
, OpenAPI._schemaMaxItems = swaggerSchema ^. Swagger.paramSchema . Swagger.maxItems
, OpenAPI._schemaMinItems = swaggerSchema ^. Swagger.paramSchema . Swagger.minItems
, OpenAPI._schemaUniqueItems = view Swagger.uniqueItems swaggerSchema
, OpenAPI._schemaMaxProperties = view Swagger.maxProperties swaggerSchema
, OpenAPI._schemaMinProperties = view Swagger.minProperties swaggerSchema
, OpenAPI._schemaAdditionalProperties = view (from swagConv) <$> view Swagger.additionalProperties swaggerSchema
, OpenAPI._schemaItems = convertItems <$> view Swagger.items swaggerSchema
, OpenAPI._schemaProperties = HM.map (view (from swagConv)) $ view Swagger.properties swaggerSchema
, OpenAPI._schemaRequired = view Swagger.required swaggerSchema
, OpenAPI._schemaAllOf = map (view (from swagConv)) <$> view Swagger.allOf swaggerSchema
, OpenAPI._schemaOneOf = Nothing
, OpenAPI._schemaNot = Nothing
, OpenAPI._schemaAnyOf = Nothing
, OpenAPI._schemaDiscriminator = view (from swagConv) <$> view Swagger.discriminator swaggerSchema
, OpenAPI._schemaReadOnly = view Swagger.readOnly swaggerSchema
, OpenAPI._schemaWriteOnly = Nothing
, OpenAPI._schemaXml = view (from swagConv) <$> view Swagger.xml swaggerSchema
, OpenAPI._schemaExternalDocs = view (from swagConv) <$> view Swagger.externalDocs swaggerSchema
, OpenAPI._schemaDeprecated = Nothing
, OpenAPI._schemaMultipleOf = view Swagger.multipleOf swaggerSchema
}
toSwaggerSchema :: Schema -> Swagger.Schema
toSwaggerSchema s@Schema{..} = Swagger.Schema
{ Swagger._schemaTitle = view title s
, Swagger._schemaDescription = view description s
, Swagger._schemaRequired = _schemaRequired
, Swagger._schemaAllOf = map (view swagConv) <$> _schemaAllOf
, Swagger._schemaProperties = HM.map (view swagConv) $ _schemaProperties
, Swagger._schemaAdditionalProperties = view swagConv <$> _schemaAdditionalProperties
, Swagger._schemaDiscriminator = view swagConv <$> view discriminator s
, Swagger._schemaReadOnly = view readOnly s
, Swagger._schemaXml = view swagConv <$> _schemaXml
, Swagger._schemaExternalDocs = view swagConv <$> _schemaExternalDocs
, Swagger._schemaExample = view example s
, Swagger._schemaMaxProperties = view maxProperties s
, Swagger._schemaMinProperties = view minProperties s
, Swagger._schemaParamSchema = Swagger.ParamSchema {
_paramSchemaDefault = _schemaDefault
, _paramSchemaType = view swagConv <$> _schemaType
, _paramSchemaFormat = _schemaFormat
, _paramSchemaItems = convertItems' <$> _schemaItems
, _paramSchemaMaximum = _schemaMaximum
, _paramSchemaExclusiveMaximum = _schemaExclusiveMaximum
, _paramSchemaMinimum = _schemaMinimum
, _paramSchemaExclusiveMinimum = _schemaExclusiveMinimum
, _paramSchemaMaxLength = _schemaMaxLength
, _paramSchemaMinLength = _schemaMinLength
, _paramSchemaPattern = _schemaPattern
, _paramSchemaMaxItems = _schemaMaxItems
, _paramSchemaMinItems = _schemaMinItems
, _paramSchemaUniqueItems = _schemaUniqueItems
, _paramSchemaEnum = _schemaEnum
, _paramSchemaMultipleOf = _schemaMultipleOf
}
}
-- little compat-shim to avoid re-implementing 'ToSchema' and 'ToParamSchema' for each
-- and every type, while we transition away from swagger.
instance {-# OVERLAPS #-} (Typeable a, Swagger.ToParamSchema a) => ToParamSchema a where
toParamSchema p = fromParamSchema $ Swagger.toParamSchema p
instance {-# OVERLAPS #-} (Typeable a, Swagger.ToSchema a) => ToSchema a where
declareNamedSchema p = DeclareT $ \d -> do
let (toRegister, Swagger.NamedSchema swaggerName swaggerSchema) =
flip SwaggerDeclare.runDeclare (lowerD d) (Swagger.declareNamedSchema p)
pure $ (convertDefinitions toRegister, OpenAPI.NamedSchema swaggerName (openApiSchema swaggerSchema))
where
openApiSchema s = fromSwaggerSchema s
convertDefinitions :: Swagger.Definitions Swagger.Schema -> Definitions Schema
convertDefinitions = HM.map fromSwaggerSchema
lowerD :: Definitions Schema -> Swagger.Definitions Swagger.Schema
lowerD = HM.map toSwaggerSchema
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment