2018-07-20 10:22:46 +03:00
|
|
|
module Hasura.GraphQL.Transport.HTTP
|
|
|
|
( runGQ
|
2019-12-20 19:04:02 +03:00
|
|
|
, runGQBatched
|
2018-07-20 10:22:46 +03:00
|
|
|
) where
|
|
|
|
|
2018-11-23 16:02:46 +03:00
|
|
|
import qualified Network.HTTP.Types as N
|
2018-07-20 10:22:46 +03:00
|
|
|
|
2019-03-25 21:25:25 +03:00
|
|
|
import Hasura.EncJSON
|
2019-07-11 08:37:06 +03:00
|
|
|
import Hasura.GraphQL.Logging
|
2018-07-20 10:22:46 +03:00
|
|
|
import Hasura.GraphQL.Transport.HTTP.Protocol
|
2019-03-18 19:22:21 +03:00
|
|
|
import Hasura.Prelude
|
2019-03-25 21:25:25 +03:00
|
|
|
import Hasura.RQL.Types
|
2019-06-04 13:10:28 +03:00
|
|
|
import Hasura.Server.Context
|
2019-07-11 08:37:06 +03:00
|
|
|
import Hasura.Server.Utils (RequestId)
|
2020-01-23 00:55:55 +03:00
|
|
|
import Hasura.Server.Version (HasVersion)
|
2018-07-20 10:22:46 +03:00
|
|
|
|
2019-11-15 03:20:18 +03:00
|
|
|
import qualified Database.PG.Query as Q
|
2019-03-25 21:25:25 +03:00
|
|
|
import qualified Hasura.GraphQL.Execute as E
|
2019-11-26 15:14:21 +03:00
|
|
|
import qualified Hasura.Logging as L
|
2018-11-23 16:02:46 +03:00
|
|
|
|
2018-07-20 10:22:46 +03:00
|
|
|
runGQ
|
2020-01-23 00:55:55 +03:00
|
|
|
:: ( HasVersion
|
|
|
|
, MonadIO m
|
2019-07-11 08:37:06 +03:00
|
|
|
, MonadError QErr m
|
|
|
|
, MonadReader E.ExecutionCtx m
|
|
|
|
)
|
|
|
|
=> RequestId
|
2018-11-23 16:02:46 +03:00
|
|
|
-> UserInfo
|
|
|
|
-> [N.Header]
|
2019-12-20 19:04:02 +03:00
|
|
|
-> GQLReq GQLQueryText
|
2019-06-04 13:10:28 +03:00
|
|
|
-> m (HttpResponse EncJSON)
|
2019-07-11 08:37:06 +03:00
|
|
|
runGQ reqId userInfo reqHdrs req = do
|
|
|
|
E.ExecutionCtx _ sqlGenCtx pgExecCtx planCache sc scVer _ enableAL <- ask
|
2019-04-17 12:48:41 +03:00
|
|
|
execPlan <- E.getResolvedExecPlan pgExecCtx planCache
|
2019-05-16 09:13:25 +03:00
|
|
|
userInfo sqlGenCtx enableAL sc scVer req
|
2019-03-25 21:25:25 +03:00
|
|
|
case execPlan of
|
2019-04-17 12:48:41 +03:00
|
|
|
E.GExPHasura resolvedOp ->
|
2019-07-11 08:37:06 +03:00
|
|
|
flip HttpResponse Nothing <$> runHasuraGQ reqId req userInfo resolvedOp
|
2019-03-25 21:25:25 +03:00
|
|
|
E.GExPRemote rsi opDef ->
|
2019-07-11 08:37:06 +03:00
|
|
|
E.execRemoteGQ reqId userInfo reqHdrs req rsi opDef
|
2018-11-23 16:02:46 +03:00
|
|
|
|
2019-12-20 19:04:02 +03:00
|
|
|
runGQBatched
|
2020-01-23 00:55:55 +03:00
|
|
|
:: ( HasVersion
|
|
|
|
, MonadIO m
|
2019-12-20 19:04:02 +03:00
|
|
|
, MonadError QErr m
|
|
|
|
, MonadReader E.ExecutionCtx m
|
|
|
|
)
|
|
|
|
=> RequestId
|
|
|
|
-> UserInfo
|
|
|
|
-> [N.Header]
|
|
|
|
-> GQLBatchedReqs GQLQueryText
|
|
|
|
-> m (HttpResponse EncJSON)
|
|
|
|
runGQBatched reqId userInfo reqHdrs reqs =
|
|
|
|
case reqs of
|
|
|
|
GQLSingleRequest req ->
|
|
|
|
runGQ reqId userInfo reqHdrs req
|
|
|
|
GQLBatchedReqs batch -> do
|
|
|
|
-- It's unclear what we should do if we receive multiple
|
|
|
|
-- responses with distinct headers, so just do the simplest thing
|
|
|
|
-- in this case, and don't forward any.
|
2020-01-23 00:55:55 +03:00
|
|
|
let removeHeaders =
|
|
|
|
flip HttpResponse Nothing
|
|
|
|
. encJFromList
|
2019-12-31 02:18:20 +03:00
|
|
|
. map (either (encJFromJValue . encodeGQErr False) _hrBody)
|
|
|
|
try = flip catchError (pure . Left) . fmap Right
|
2020-01-23 00:55:55 +03:00
|
|
|
fmap removeHeaders $
|
2019-12-31 02:18:20 +03:00
|
|
|
traverse (try . runGQ reqId userInfo reqHdrs) batch
|
2019-12-20 19:04:02 +03:00
|
|
|
|
2018-11-23 16:02:46 +03:00
|
|
|
runHasuraGQ
|
2019-07-11 08:37:06 +03:00
|
|
|
:: ( MonadIO m
|
|
|
|
, MonadError QErr m
|
|
|
|
, MonadReader E.ExecutionCtx m
|
|
|
|
)
|
|
|
|
=> RequestId
|
|
|
|
-> GQLReqUnparsed
|
2018-11-23 16:02:46 +03:00
|
|
|
-> UserInfo
|
2019-04-17 12:48:41 +03:00
|
|
|
-> E.ExecOp
|
2019-03-18 19:22:21 +03:00
|
|
|
-> m EncJSON
|
2019-07-11 08:37:06 +03:00
|
|
|
runHasuraGQ reqId query userInfo resolvedOp = do
|
|
|
|
E.ExecutionCtx logger _ pgExecCtx _ _ _ _ _ <- ask
|
2019-04-17 12:48:41 +03:00
|
|
|
respE <- liftIO $ runExceptT $ case resolvedOp of
|
2019-07-11 08:37:06 +03:00
|
|
|
E.ExOpQuery tx genSql -> do
|
|
|
|
-- log the generated SQL and the graphql query
|
2019-11-26 15:14:21 +03:00
|
|
|
L.unLogger logger $ QueryLog query genSql reqId
|
2019-04-17 12:48:41 +03:00
|
|
|
runLazyTx' pgExecCtx tx
|
2019-07-11 08:37:06 +03:00
|
|
|
E.ExOpMutation tx -> do
|
|
|
|
-- log the graphql query
|
2019-11-26 15:14:21 +03:00
|
|
|
L.unLogger logger $ QueryLog query Nothing reqId
|
2019-11-15 03:20:18 +03:00
|
|
|
runLazyTx pgExecCtx Q.ReadWrite $ withUserInfo userInfo tx
|
2019-04-17 12:48:41 +03:00
|
|
|
E.ExOpSubs _ ->
|
2019-03-25 21:25:25 +03:00
|
|
|
throw400 UnexpectedPayload
|
|
|
|
"subscriptions are not supported over HTTP, use websockets instead"
|
2019-04-17 12:48:41 +03:00
|
|
|
resp <- liftEither respE
|
2019-03-18 19:22:21 +03:00
|
|
|
return $ encodeGQResp $ GQSuccess $ encJToLBS resp
|