@@ -6,9 +6,10 @@ import Affjax as AX
6import Affjax.RequestBody as RequestBody
6import Affjax.RequestBody as RequestBody
7import Affjax.RequestHeader (RequestHeader(..))
7import Affjax.RequestHeader (RequestHeader(..))
8import Affjax.ResponseFormat as ResponseFormat
8import Affjax.ResponseFormat as ResponseFormat
9−import Control.Monad.Error.Class (class MonadError, class MonadThrow)
9+import Control.Monad.Error.Class (class MonadThrow)
10import Data.Either (Either(..))
10import Data.Either (Either(..))
11import Data.HTTP.Method (Method(..))
11import Data.HTTP.Method (Method(..))
12+import Data.List.Types (NonEmptyList)
12import Data.Maybe (Maybe(..))
13import Data.Maybe (Maybe(..))
13import Data.MediaType (MediaType(..))
14import Data.MediaType (MediaType(..))
14import Data.String as String
15import Data.String as String
@@ -17,35 +18,113 @@ import Effect.Aff (Aff, error, throwError)
17import Effect.Aff.Class (class MonadAff, liftAff)
18import Effect.Aff.Class (class MonadAff, liftAff)
18import Effect.Class (liftEffect)
19import Effect.Class (liftEffect)
19import Effect.Class.Console as Log
20import Effect.Class.Console as Log
21+import Foreign (ForeignError)
20import Simple.JSON as JSON
22import Simple.JSON as JSON
21import Type.Proxy (Proxy(..))
23import Type.Proxy (Proxy(..))
23data GraphQL
25data GraphQL
25−data Gql (operation :: GraphQL)
27+data Gql (operation :: GraphQL) = Gql
28−class GraphQLReqRes (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type) | operation -> gql i o
29+class
31+ (operation :: GraphQL)
35+ | operation -> gql i o
30type Endpoint = String
37type Endpoint = String
38+type NetworkErrorInfo =
39+ { endpoint :: Endpoint
40+ , requestHeaders :: Array RequestHeader
41+ , requestBody :: String
32−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 }
45+type ParsingErrorInfo =
46+ { endpoint :: Endpoint
47+ , requestHeaders :: Array RequestHeader
48+ , requestBody :: String
49+ , response :: AX.Response String
50+ , jsonParsingError :: NonEmptyList ForeignError
34−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
53+type GraphQLClient'
54+ (operation :: GraphQL)
60+ GraphQLReqRes operation gql i o
62+ => JSON.WriteForeign { | i }
63+ => JSON.ReadForeign { | o }
66+ => (NetworkErrorInfo -> e)
67+ -> (ParsingErrorInfo -> e)
73+ forall (operation :: GraphQL)
74+ (gql :: Symbol) (i :: Row Type) (o :: Row Type) (m :: Type -> Type) (e :: Type)
75+ . GraphQLClient' operation gql i o m e
79+ -> Array RequestHeader
36−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 })
80+ -> ( forall (operation :: GraphQL) (gql :: Symbol) (i :: Row Type) (o :: Row Type)
81+ . GraphQLReqRes operation gql i o
83+ => JSON.WriteForeign { | i }
84+ => JSON.ReadForeign { | o }
37−graphQL endpoint headers = graphQL' endpoint headers (error <<< AX.printError) (error <<< _.body)
89+graphQL endpoint headers = graphQL'
92+ (error <<< AX.printError <<< _.error)
93+ (error <<< _.body <<< _.response)
39graphQL' :: Endpoint -> Array RequestHeader -> GraphQLClient
95graphQL' :: Endpoint -> Array RequestHeader -> GraphQLClient
40−graphQL' endpoint headers = go
96+graphQL' endpoint headers' = go
42− 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 }
98+ requestHeaders = headers' <> [ ContentType $ MediaType "application/json" ]
101+ :: forall (operation :: GraphQL) (gql :: Symbol)
102+ (i :: Row Type) (o :: Row Type) (m :: Type -> Type) (e :: Type)
103+ . GraphQLReqRes operation gql i o
105+ => JSON.WriteForeign
107+ => JSON.ReadForeign { | o }
110+ => (NetworkErrorInfo -> e)
111+ -> (ParsingErrorInfo -> e)
43 go networkErrorF readErrorF _ variables = do
115 go networkErrorF readErrorF _ variables = do
46 { variables
118 { variables
47− , query: String.replaceAll (String.Pattern "\n") (String.Replacement " ") (String.replaceAll (String.Pattern "\r\n") (String.Replacement " ") (reflectSymbol (Proxy :: Proxy gql)))
119+ , query: String.replaceAll (String.Pattern "\n")
120+ (String.Replacement " ")
122+ (String.Pattern "\r\n")
123+ (String.Replacement " ")
124+ (reflectSymbol (Proxy :: Proxy gql))
127+ requestBody = JSON.writeJSON input
50 liftAff $ AX.request
129 liftAff $ AX.request
51 ( AX.defaultRequest
130 ( AX.defaultRequest
@@ -53,15 +132,23 @@ graphQL' endpoint headers = go
53 , method = Left POST
132 , method = Left POST
54 , responseFormat = ResponseFormat.string
133 , responseFormat = ResponseFormat.string
55 , content =
134 , content =
57− (RequestBody.string (JSON.writeJSON input))
136+ (RequestBody.string requestBody)
58− , headers = headers <> [ContentType $ MediaType "application/json"]
137+ , headers = requestHeaders
61 case res of
140 case res of
62− Left err -> do
141+ Left error -> do
63 liftEffect $ Log.info "Request did not go through"
142 liftEffect $ Log.info "Request did not go through"
64− throwError (networkErrorF err)
143+ throwError (networkErrorF { endpoint, requestHeaders, error, requestBody })
65 Right response -> case (JSON.readJSON response.body) of
144 Right response -> case (JSON.readJSON response.body) of
145+ Left jsonParsingError -> throwError
66− Left _ -> throwError (readErrorF response)
146+ ( readErrorF
67 Right ({ data: d } :: { data :: { | o } }) -> pure d
154 Right ({ data: d } :: { data :: { | o } }) -> pure d