mirror of
https://github.com/rowtype-yoga/purescript-graphql-fundeps.git
synced 2024-11-25 07:07:45 +03:00
Adds better error handler
This commit is contained in:
parent
a46a03592e
commit
018f8c702b
10
package-lock.json
generated
10
package-lock.json
generated
@ -11,6 +11,7 @@
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"purescript": "^0.14.1",
|
||||
"purs-tidy": "^0.10.0",
|
||||
"spago": "^0.20.3",
|
||||
"xhr2": "^0.2.1"
|
||||
}
|
||||
@ -1119,6 +1120,15 @@
|
||||
"node": ">=8.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/purs-tidy": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/purs-tidy/-/purs-tidy-0.10.0.tgz",
|
||||
"integrity": "sha512-ULbJfBHRngczYwcOzugytRiNy+Guy2VXoAG1jMtGaSFEaUZk1lZkKU11t8jIZTrDdOrkgqlWCZLi3mfcHvdimA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"purs-tidy": "bin/index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"purescript": "^0.14.1",
|
||||
"purs-tidy": "^0.10.0",
|
||||
"spago": "^0.20.3",
|
||||
"xhr2": "^0.2.1"
|
||||
}
|
||||
|
121
src/GraphQL.purs
121
src/GraphQL.purs
@ -6,9 +6,10 @@ import Affjax as AX
|
||||
import Affjax.RequestBody as RequestBody
|
||||
import Affjax.RequestHeader (RequestHeader(..))
|
||||
import Affjax.ResponseFormat as ResponseFormat
|
||||
import Control.Monad.Error.Class (class MonadError, class MonadThrow)
|
||||
import Control.Monad.Error.Class (class MonadThrow)
|
||||
import Data.Either (Either(..))
|
||||
import Data.HTTP.Method (Method(..))
|
||||
import Data.List.Types (NonEmptyList)
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.MediaType (MediaType(..))
|
||||
import Data.String as String
|
||||
@ -17,35 +18,113 @@ import Effect.Aff (Aff, error, throwError)
|
||||
import Effect.Aff.Class (class MonadAff, liftAff)
|
||||
import Effect.Class (liftEffect)
|
||||
import Effect.Class.Console as Log
|
||||
import Foreign (ForeignError)
|
||||
import Simple.JSON as JSON
|
||||
import Type.Proxy (Proxy(..))
|
||||
|
||||
data GraphQL
|
||||
|
||||
data Gql (operation :: GraphQL)
|
||||
= Gql
|
||||
data Gql (operation :: GraphQL) = Gql
|
||||
|
||||
class GraphQLReqRes (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type) | operation -> gql i o
|
||||
class
|
||||
GraphQLReqRes
|
||||
(operation :: GraphQL)
|
||||
(gql :: Symbol)
|
||||
(i :: Row Type)
|
||||
(o :: Row Type)
|
||||
| operation -> gql i o
|
||||
|
||||
type Endpoint = String
|
||||
type NetworkErrorInfo =
|
||||
{ endpoint :: Endpoint
|
||||
, requestHeaders :: Array RequestHeader
|
||||
, requestBody :: String
|
||||
, error :: AX.Error
|
||||
}
|
||||
|
||||
type GraphQLClient' (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type) (m :: Type -> Type) (e :: Type) = GraphQLReqRes operation gql i o => IsSymbol gql => JSON.WriteForeign { | i } => JSON.ReadForeign { | o } => MonadAff m => MonadThrow e m => MonadError e m => (AX.Error -> e) -> (AX.Response String -> e) ->Gql operation -> Record i -> m { | o }
|
||||
type ParsingErrorInfo =
|
||||
{ endpoint :: Endpoint
|
||||
, requestHeaders :: Array RequestHeader
|
||||
, requestBody :: String
|
||||
, response :: AX.Response String
|
||||
, jsonParsingError :: NonEmptyList ForeignError
|
||||
}
|
||||
|
||||
type GraphQLClient = forall (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type) (m :: Type -> Type) (e :: Type). GraphQLClient' operation gql i o m e
|
||||
type GraphQLClient'
|
||||
(operation :: GraphQL)
|
||||
(gql :: Symbol)
|
||||
(i :: Row Type)
|
||||
(o :: Row Type)
|
||||
(m :: Type -> Type)
|
||||
(e :: Type) =
|
||||
GraphQLReqRes operation gql i o
|
||||
=> IsSymbol gql
|
||||
=> JSON.WriteForeign { | i }
|
||||
=> JSON.ReadForeign { | o }
|
||||
=> MonadAff m
|
||||
=> MonadThrow e m
|
||||
=> (NetworkErrorInfo -> e)
|
||||
-> (ParsingErrorInfo -> e)
|
||||
-> Gql operation
|
||||
-> Record i
|
||||
-> m { | o }
|
||||
|
||||
graphQL :: Endpoint -> Array RequestHeader -> (forall (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type). GraphQLReqRes operation gql i o => IsSymbol gql => JSON.WriteForeign { | i } => JSON.ReadForeign { | o } => Gql operation -> Record i -> Aff { | o })
|
||||
graphQL endpoint headers = graphQL' endpoint headers (error <<< AX.printError) (error <<< _.body)
|
||||
type GraphQLClient =
|
||||
forall (operation :: GraphQL)
|
||||
(gql :: Symbol) (i :: Row Type) (o :: Row Type) (m :: Type -> Type) (e :: Type)
|
||||
. GraphQLClient' operation gql i o m e
|
||||
|
||||
graphQL
|
||||
:: Endpoint
|
||||
-> Array RequestHeader
|
||||
-> ( forall (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type)
|
||||
. GraphQLReqRes operation gql i o
|
||||
=> IsSymbol gql
|
||||
=> JSON.WriteForeign { | i }
|
||||
=> JSON.ReadForeign { | o }
|
||||
=> Gql operation
|
||||
-> Record i
|
||||
-> Aff { | o }
|
||||
)
|
||||
graphQL endpoint headers = graphQL'
|
||||
endpoint
|
||||
headers
|
||||
(error <<< AX.printError <<< _.error)
|
||||
(error <<< _.body <<< _.response)
|
||||
|
||||
graphQL' :: Endpoint -> Array RequestHeader -> GraphQLClient
|
||||
graphQL' endpoint headers = go
|
||||
graphQL' endpoint headers' = go
|
||||
where
|
||||
go :: forall (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type) (m :: Type -> Type) (e :: Type). GraphQLReqRes operation gql i o => IsSymbol gql => JSON.WriteForeign { | i } => JSON.ReadForeign { | o } => MonadAff m => MonadThrow e m => MonadError e m => (AX.Error -> e) -> (AX.Response String -> e) ->Gql operation -> Record i -> m { | o }
|
||||
requestHeaders = headers' <> [ ContentType $ MediaType "application/json" ]
|
||||
|
||||
go
|
||||
:: forall (operation :: GraphQL) (gql :: Symbol)
|
||||
(i :: Row Type) (o :: Row Type) (m :: Type -> Type) (e :: Type)
|
||||
. GraphQLReqRes operation gql i o
|
||||
=> IsSymbol gql
|
||||
=> JSON.WriteForeign
|
||||
{ | i }
|
||||
=> JSON.ReadForeign { | o }
|
||||
=> MonadAff m
|
||||
=> MonadThrow e m
|
||||
=> (NetworkErrorInfo -> e)
|
||||
-> (ParsingErrorInfo -> e)
|
||||
-> Gql operation
|
||||
-> Record i
|
||||
-> m { | o }
|
||||
go networkErrorF readErrorF _ variables = do
|
||||
let
|
||||
input =
|
||||
{ variables
|
||||
, query: String.replaceAll (String.Pattern "\n") (String.Replacement " ") (String.replaceAll (String.Pattern "\r\n") (String.Replacement " ") (reflectSymbol (Proxy :: Proxy gql)))
|
||||
, query: String.replaceAll (String.Pattern "\n")
|
||||
(String.Replacement " ")
|
||||
( String.replaceAll
|
||||
(String.Pattern "\r\n")
|
||||
(String.Replacement " ")
|
||||
(reflectSymbol (Proxy :: Proxy gql))
|
||||
)
|
||||
}
|
||||
requestBody = JSON.writeJSON input
|
||||
res <-
|
||||
liftAff $ AX.request
|
||||
( AX.defaultRequest
|
||||
@ -53,15 +132,23 @@ graphQL' endpoint headers = go
|
||||
, method = Left POST
|
||||
, responseFormat = ResponseFormat.string
|
||||
, content =
|
||||
Just
|
||||
(RequestBody.string (JSON.writeJSON input))
|
||||
, headers = headers <> [ContentType $ MediaType "application/json"]
|
||||
Just
|
||||
(RequestBody.string requestBody)
|
||||
, headers = requestHeaders
|
||||
}
|
||||
)
|
||||
case res of
|
||||
Left err -> do
|
||||
Left error -> do
|
||||
liftEffect $ Log.info "Request did not go through"
|
||||
throwError (networkErrorF err)
|
||||
throwError (networkErrorF { endpoint, requestHeaders, error, requestBody })
|
||||
Right response -> case (JSON.readJSON response.body) of
|
||||
Left _ -> throwError (readErrorF response)
|
||||
Left jsonParsingError -> throwError
|
||||
( readErrorF
|
||||
{ endpoint
|
||||
, requestHeaders
|
||||
, jsonParsingError
|
||||
, requestBody
|
||||
, response
|
||||
}
|
||||
)
|
||||
Right ({ data: d } :: { data :: { | o } }) -> pure d
|
Loading…
Reference in New Issue
Block a user