-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathapollo.re
More file actions
136 lines (103 loc) · 3.48 KB
/
apollo.re
File metadata and controls
136 lines (103 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
let httpLink = ApolloLinks.createHttpLink(~uri=Config.graphqlURI, ());
let makeAuthLink = (auth) => {
let contextHandler = () => { "headers": { "authorization": auth } };
ApolloLinks.createContextLink(contextHandler)
};
type dataObject = {. "__typename": string, "id": string, "key": string };
let inMemoryCache = ApolloInMemoryCache.createInMemoryCache(
~dataIdFromObject=(obj: dataObject) => obj##id,
()
);
module Client = ReasonApollo.CreateClient({
let links = switch (Config.graphqlAuthHeader) {
| None => [|httpLink|]
| Some(auth) => [|makeAuthLink(auth), httpLink|]
};
let apolloClient = ReasonApollo.createApolloClient(
~cache=inMemoryCache,
~link=ApolloLinks.from(links),
()
);
});
[@bs.send] external resetStoreOfClient
: (ApolloClient.generatedApolloClient) => Js.Promise.t(unit)
= "resetStore";
let resetStore = () => resetStoreOfClient(Client.apolloClient);
type errorCode =
[ `BadRequest | `InternalServerError ];
type error = {. "code": errorCode, "message": string };
exception ResponseError(errorCode, string);
module type RequestConfig = {
type payload;
type response;
let deconstructResponse: (response) => (option(payload), option(error))
};
module Request = (Conf: RequestConfig) => {
external castResponse : string => {. "data": Js.Json.t } = "%identity";
[@bs.module] external gql : ReasonApolloTypes.gql = "graphql-tag";
type gqlQuery = {.
"query": string,
"variables": Js.Json.t,
"parse": (Js.Json.t) => Conf.response
};
type request =
[ `Mutation(gqlQuery)
| `Query(gqlQuery) ];
let gqlQueryOfRequest : (request) => gqlQuery = fun
| `Mutation(q) | `Query(q) => q;
exception SendFailure(Js.Promise.error, gqlQuery);
type result =
[ `Payload(Conf.payload)
| `Exn(exn) ];
let send = (~request) => {
let module P = Js.Promise;
let requestPromise = switch request {
| `Query(query) =>
Client.apolloClient##query({
"query": [@bs] gql(query##query),
"variables": query##variables
})
| `Mutation(mutation) =>
Client.apolloClient##mutate({
"mutation": [@bs] gql(mutation##query),
"variables": mutation##variables
})
};
let gqlQuery = gqlQueryOfRequest(request);
P.make((~resolve, ~reject as _) => {
/* This promise is never rejected since, as of writing, there does not
seem to be any good way with dealing with the `Js.Promise.error`
abstract type. */
P.resolve(requestPromise)
|> P.then_((result) => {
let typedResult = castResponse(result)##data |> gqlQuery##parse;
let (payload, error) = Conf.deconstructResponse(typedResult);
switch (payload, error) {
| (_payload, Some(error)) =>
[@bs] resolve(`Exn(ResponseError(error##code, error##message)))
| (None, None) =>
[@bs] resolve(`Exn(ResponseError(`InternalServerError,
"Payload and error are null.")))
| (Some(payload), _error) =>
[@bs] resolve(`Payload(payload))
};
P.resolve()
})
|> P.catch((error) => {
[@bs] resolve(`Exn(SendFailure(error, gqlQuery)));
P.resolve()
})
|> ignore
})
};
};
let messageOfExn = (failedAction, ~id, ~exn) => {
let prefix = "Failed " ++ failedAction;
switch exn {
| ResponseError(_code, message) =>
prefix ++ ": " ++ message
| exn =>
Js.log3(prefix, id, exn);
prefix ++ ". See console."
}
};