1
Fork 0
mirror of https://github.com/Airsequel/AirGQL.git synced 2025-07-08 11:09:32 +02:00
airgql/source/Server/Server.hs

194 lines
4.9 KiB
Haskell

-- Necessary for servant-docs instances
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
module Server.Server (platformAPI, platformApp)
where
import Protolude (
Int,
Monoid (mempty),
Proxy (Proxy),
($),
)
import Protolude qualified as P
import Data.Aeson (Object, Value, object)
import Data.Aeson.KeyMap qualified as KeyMap
import Data.ByteString.Lazy qualified as BL
import Data.Text (Text)
import Data.Text qualified as T
import Network.Wai (Application)
import Network.Wai.Parse (
defaultParseRequestBodyOptions,
setMaxRequestFilesSize,
setMaxRequestNumFiles,
)
import Servant (Context (EmptyContext, (:.)), NoContent)
import Servant.API (
Capture,
Get,
JSON,
PlainText,
Post,
ReqBody,
(:<|>) ((:<|>)),
(:>),
)
import Servant.Docs (
DocCapture (DocCapture),
ToCapture (toCapture),
ToSample,
singleSample,
toSamples,
)
import Servant.HTML.Blaze (HTML)
import Servant.Multipart (
MultipartData (MultipartData),
MultipartOptions (generalOptions),
Tmp,
ToMultipartSample (toMultipartSamples),
defaultMultipartOptions,
)
import Servant.Server (Server)
import Servant.Server qualified as Servant
import Text.Blaze.Internal (MarkupM)
import AirGQL.Config (Config (maxDbSize), defaultConfig)
import AirGQL.ExternalAppContext (ExternalAppContext)
import AirGQL.Lib (SQLPost)
import AirGQL.Servant.Database (
apiDatabaseSchemaGetHandler,
apiDatabaseVacuumPostHandler,
)
import AirGQL.Servant.GraphQL (
gqlQueryGetHandler,
gqlQueryPostHandler,
playgroundDefaultQueryHandler,
readOnlyGqlPostHandler,
writeOnlyGqlPostHandler,
)
import AirGQL.Servant.SqlQuery (sqlQueryPostHandler)
import AirGQL.Types.SchemaConf (SchemaConf (pragmaConf), defaultSchemaConf)
import AirGQL.Types.SqlQueryPostResult (SqlQueryPostResult)
import AirGQL.Types.Types (GQLPost)
{- FOURMOLU_DISABLE -}
-- ATTENTION: Order of handlers matters!
type PlatformAPI =
-- gqlQueryGetHandler
-- Redirect to GraphiQL playground
"graphql" :> Get '[HTML] NoContent
-- gqlQueryPostHandler
:<|> "graphql"
:> ReqBody '[JSON] GQLPost
:> Post '[JSON] Object
-- writeOnlyGqlPostHandler
:<|> "readonly" :> "graphql"
:> ReqBody '[JSON] GQLPost
:> Post '[JSON] Object
-- writeOnlyGqlPostHandler
:<|> "writeonly" :> "graphql"
:> ReqBody '[JSON] GQLPost
:> Post '[JSON] Object
-- playgroundDefaultQueryHandler
:<|> "playground" :> "default-query"
:> Get '[PlainText] Text
-- apiDatabaseSchemaGetHandler
:<|> "schema" :> Get '[PlainText] Text
-- apiDatabaseVacuumPostHandler
:<|> "vacuum" :> Post '[JSON] Object
-- sqlQueryPostHandler
:<|> "sql"
:> ReqBody '[JSON] SQLPost
:> Post '[JSON] SqlQueryPostResult
{- FOURMOLU_ENABLE -}
-- | Instances for automatic documentation generation via servant-docs
instance ToSample (MultipartData Tmp) where
toSamples _ = singleSample $ MultipartData mempty mempty
instance ToMultipartSample Tmp (MultipartData Tmp) where
toMultipartSamples _ = []
instance ToSample Value where
toSamples _ = singleSample $ object []
instance ToSample (KeyMap.KeyMap Value) where
toSamples _ = singleSample $ KeyMap.fromList []
instance ToSample (MarkupM ()) where
toSamples _ = singleSample mempty
instance ToSample BL.ByteString where
toSamples _ = singleSample mempty
instance ToSample Text where
toSamples _ = singleSample mempty
instance ToSample P.ByteString where
toSamples _ = singleSample mempty
instance ToCapture (Capture "readonlyId" Text) where
toCapture _ = DocCapture "readonlyId" "Read-only ID of the database"
instance ToCapture (Capture "dbId" Text) where
toCapture _ = DocCapture "dbId" "ID of the database to be served"
platformAPI :: Proxy PlatformAPI
platformAPI = Proxy
platformServer :: ExternalAppContext -> P.FilePath -> Server PlatformAPI
platformServer ctx filePath = do
let dbPath = T.pack filePath
gqlQueryGetHandler dbPath
:<|> gqlQueryPostHandler defaultSchemaConf dbPath
:<|> readOnlyGqlPostHandler dbPath
:<|> writeOnlyGqlPostHandler dbPath
:<|> playgroundDefaultQueryHandler dbPath
:<|> apiDatabaseSchemaGetHandler ctx dbPath
:<|> apiDatabaseVacuumPostHandler dbPath
:<|> sqlQueryPostHandler defaultSchemaConf.pragmaConf dbPath
platformApp :: ExternalAppContext -> P.FilePath -> Application
platformApp ctx filePath = do
let
maxFileSizeInByte :: Int = defaultConfig.maxDbSize
multipartOpts :: MultipartOptions Tmp
multipartOpts =
(defaultMultipartOptions (Proxy :: Proxy Tmp))
{ generalOptions =
setMaxRequestNumFiles 1 $
setMaxRequestFilesSize
(P.fromIntegral maxFileSizeInByte)
defaultParseRequestBodyOptions
}
context :: Context '[MultipartOptions Tmp]
context =
multipartOpts :. EmptyContext
Servant.serveWithContext platformAPI context $ platformServer ctx filePath