UNPKG

12.2 kBMarkdownView Raw
1---
2title: apollo-link-http
3description: Get GraphQL results over a network using HTTP fetch.
4---
5
6The http link is the most common Apollo Link, a system of modular components
7for GraphQL networking. If you haven't done so already, [read the Apollo Link
8docs](https://www.apollographql.com/docs/link/#usage) to learn about the Apollo
9Link ecosystem and how to use this link with libraries like Apollo Client and
10graphql-tools, or as a standalone client.
11
12The http link is a terminating link that fetches GraphQL results from a GraphQL
13endpoint over an http connection. The http link supports both POST and GET
14requests with the ability to change the http options on a per query basis. This
15can be used for authentication, persisted queries, dynamic uris, and other
16granular updates.
17
18<h2 id="usage">Usage</h2>
19
20Import and initialize this link in just two lines:
21
22```js
23import { createHttpLink } from "apollo-link-http";
24
25const link = createHttpLink({ uri: "/graphql" });
26```
27
28<h2 id="options">Options</h2>
29
30HTTP Link takes an object with some options on it to customize the behavior of the link. If your server supports it, the HTTP link can also send over metadata about the request in the extensions field. To enable this, pass `includeExtensions` as true. The options you can pass are outlined below:
31
32* `uri`: the URI key is a string endpoint or function resolving to an endpoint -- will default to "/graphql" if not specified
33* `includeExtensions`: allow passing the extensions field to your graphql server, defaults to false
34* `fetch`: a `fetch` compatible API for making a request
35* `headers`: an object representing values to be sent as headers on the request
36* `credentials`: a string representing the credentials policy you want for the fetch call. Possible values are: `omit`, `include` and `same-origin`
37* `fetchOptions`: any overrides of the fetch options argument to pass to the fetch call
38* `useGETForQueries`: set to `true` to use the HTTP `GET` method for queries (but not for mutations)
39
40<h2 id="fetch">Fetch polyfill</h2>
41
42The HTTP Link relies on having `fetch` present in your runtime environment. If you are running on react-native, or modern browsers, this should be no problem. If you are targeting an environment without `fetch` such as older browsers or the server, you will need to pass your own `fetch` to the link through the options. We recommend [`unfetch`](https://github.com/developit/unfetch) for older browsers and [`node-fetch`](https://github.com/bitinn/node-fetch) for running in Node.
43
44<h2 id="context">Context</h2>
45
46The Http Link uses the `headers` field on the context to allow passing headers to the HTTP request. It also supports the `credentials` field for defining credentials policy, `uri` for changing the endpoint dynamically, and `fetchOptions` to allow generic fetch overrides (i.e. `method: "GET"`). These options will override the same key if passed when creating the the link.
47
48Note that if you set `fetchOptions.method` to `GET`, the http link will follow the [standard GraphQL HTTP GET encoding](http://graphql.org/learn/serving-over-http/#get-request): the query, variables, operation name, and extensions will be passed as query parameters rather than in the HTTP request body. If you want mutations to continue to be sent as non-idempotent `POST` requests, set the top-level `useGETForQueries` option to `true` instead of setting `fetchOptions.method` to `GET`.
49
50This link also attaches the response from the `fetch` operation on the context as `response` so you can access it from within another link.
51
52* `headers`: an object representing values to be sent as headers on the request
53* `credentials`: a string representing the credentials policy you want for the fetch call. Possible values are: `omit`, `include` and `same-origin`
54* `uri`: a string of the endpoint you want to fetch from
55* `fetchOptions`: any overrides of the fetch options argument to pass to the fetch call
56* `response`: this is the raw response from the fetch request after it is made.
57* `http`: this is an object to control fine grained aspects of the http link itself, such as persisted queries (see below)
58
59<h3 id="persisted-queries">Persisted queries</h3>
60
61The http link supports an advanced GraphQL feature called persisted queries. This allows you to not send the stringified query over the wire, but instead send some kind of identifier of the query. To support this you need to attach the id somewhere to the extensions field and pass the following options to the context:
62
63```js
64operation.setContext({
65 http: {
66 includeExtensions: true,
67 includeQuery: false,
68 }
69})
70```
71
72The `http` object on context currently supports two keys:
73
74* `includeExtensions`: Send the extensions object for this request.
75* `includeQuery`: Don't send the `query` field for this request.
76
77One way to use persisted queries is with [apollo-link-persisted-queries](https://github.com/apollographql/apollo-link-persisted-queries) and [Apollo Engine](https://www.apollographql.com/docs/engine/auto-persisted-queries.html).
78
79<h3 id="passing-context">Passing context per query</h3>
80
81Apollo Client supports passing context separately for every query, so you can do things like pass a special header for a single query invocation if you need to.
82
83```js
84import { createHttpLink } from "apollo-link-http";
85import ApolloClient from "apollo-client";
86import { InMemoryCache } from "apollo-cache-inmemory";
87
88const client = new ApolloClient({
89 link: createHttpLink({ uri: "/graphql" }),
90 cache: new InMemoryCache()
91});
92
93// a query with apollo-client
94client.query({
95 query: MY_QUERY,
96 context: {
97 // example of setting the headers with context per operation
98 headers: {
99 special: "Special header value"
100 }
101 }
102});
103```
104
105<h2 id="error">Errors</h2>
106
107The Http Link draws a distinction between client, server and GraphQL errors. Server errors can occur in three different scenarios: parse, network and data errors. [`apollo-link-error`](error.html) provides an [interface](error.html#Usage) for handling these errors. This list describes the scenarios that cause different errors:
108
109* _Client parse error_: the request body is not-serializable due to circular references for example
110* _Server parse error_: the response from the server cannot be parsed ([response.json()](https://developer.mozilla.org/en-US/docs/Web/API/Body/json))
111* _Server network error_: the response has a status of >= 300
112* _Server data error_: the parse request does not contain `data` or `errors`
113* _GraphQL error_: an objects in the `errors` array for a 200 level status
114
115Since many server implementations can return a valid GraphQL result on a server network error, the thrown `Error` object contains the parsed server result. A server data error also receives the parsed result.
116
117The table below provides a summary of error, `Observable` method called by the HTTP link, and type of error thrown for each failure:
118
119| Error | Callback | Error Type |
120| -------------- | :------: | ------------------ |
121| Client Parse | `error` | `ClientParseError` |
122| Server Parse | `error` | `ServerParseError` |
123| Server Network | `error` | `ServerError` |
124| Server Data | `error` | `ServerError` |
125| GraphQL Error | `next` | `Object` |
126
127All error types inherit the `name`, `message`, and nullable `stack` properties from the generic javascript [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error).
128
129```js
130//type ClientParseError
131{
132 parseError: Error; // Error returned from response.json()
133};
134
135//type ServerParseError
136{
137 response: Response; // Object returned from fetch()
138 statusCode: number; // HTTP status code
139 bodyText: string // text that was returned from server
140};
141
142//type ServerError
143{
144 result: Record<string, any>; // Parsed object from server response
145 response: Response; // Object returned from fetch()
146 statusCode: number; // HTTP status code
147};
148```
149
150<h2 id="custom">Custom fetching</h2>
151
152You can use the `fetch` option when creating an http-link to do a lot of custom networking. This is useful if you want to modify the request based on the calculated headers or calculate the uri based on the operation:
153
154<h3 id="custom-auth">Custom auth</h3>
155
156```js
157const customFetch = (uri, options) => {
158 const { header } = Hawk.client.header(
159 "http://example.com:8000/resource/1?b=1&a=2",
160 "POST",
161 { credentials: credentials, ext: "some-app-data" }
162 );
163 options.headers.Authorization = header;
164 return fetch(uri, options);
165};
166
167const link = createHttpLink({ fetch: customFetch });
168```
169
170<h3 id="dynamic-uri">Dynamic URI</h3>
171
172```js
173const customFetch = (uri, options) => {
174 const { operationName } = JSON.parse(options.body);
175 return fetch(`${uri}/graph/graphql?opname=${operationName}`, options);
176};
177
178const link = createHttpLink({ fetch: customFetch });
179```
180
181<h2 id="upgrading">Upgrade: Apollo Client 1.0</h2>
182
183If you previously used either `apollo-fetch` or `apollo-client`'s `createNetworkInterface`, you will need to change the way `use` and `useAfter` are implemented in your app. Both can be implemented by writing a custom link. It's important to note that regardless of whether you're adding middleware or afterware, your Http link will always be last in the chain since it's a terminating link.
184
185#### Middleware
186
187_Before_
188
189```js
190// before
191import ApolloClient, { createNetworkInterface } from "apollo-client";
192
193const networkInterface = createNetworkInterface({ uri: "/graphql" });
194
195networkInterface.use([
196 {
197 applyMiddleware(req, next) {
198 if (!req.options.headers) {
199 req.options.headers = {}; // Create the header object if needed.
200 }
201 req.options.headers["authorization"] = localStorage.getItem("token")
202 ? localStorage.getItem("token")
203 : null;
204 next();
205 }
206 }
207]);
208```
209
210_After_
211
212```js
213import { ApolloLink } from "apollo-link";
214import { createHttpLink } from "apollo-link-http";
215
216const httpLink = createHttpLink({ uri: "/graphql" });
217const middlewareLink = new ApolloLink((operation, forward) => {
218 operation.setContext({
219 headers: {
220 authorization: localStorage.getItem("token") || null
221 }
222 });
223 return forward(operation);
224});
225
226// use with apollo-client
227const link = middlewareLink.concat(httpLink);
228```
229
230#### Afterware (error)
231
232_Before_
233
234```js
235import ApolloClient, { createNetworkInterface } from "apollo-client";
236import { logout } from "./logout";
237
238const networkInterface = createNetworkInterface({ uri: "/graphql" });
239
240networkInterface.useAfter([
241 {
242 applyAfterware({ response }, next) {
243 if (response.statusCode === 401) {
244 logout();
245 }
246 next();
247 }
248 }
249]);
250```
251
252_After_
253
254```js
255import { ApolloLink } from "apollo-link";
256import { createHttpLink } from "apollo-link-http";
257import { onError } from "apollo-link-error";
258
259import { logout } from "./logout";
260
261const httpLink = createHttpLink({ uri: "/graphql" });
262const errorLink = onError(({ networkError }) => {
263 if (networkError.statusCode === 401) {
264 logout();
265 }
266});
267
268// use with apollo-client
269const link = errorLink.concat(httpLink);
270```
271
272#### Afterware (data manipulation)
273
274_Before_
275
276```js
277import ApolloClient, { createNetworkInterface } from "apollo-client";
278
279const networkInterface = createNetworkInterface({ uri: "/graphql" });
280
281networkInterface.useAfter([
282 {
283 applyAfterware({ response }, next) {
284 if (response.data.user.lastLoginDate) {
285 response.data.user.lastLoginDate = new Date(
286 response.data.user.lastLoginDate
287 );
288 }
289 next();
290 }
291 }
292]);
293```
294
295_After_
296
297```js
298import { ApolloLink } from "apollo-link";
299import { createHttpLink } from "apollo-link-http";
300
301const httpLink = createHttpLink({ uri: "/graphql" });
302const addDatesLink = new ApolloLink((operation, forward) => {
303 return forward(operation).map(response => {
304 if (response.data.user.lastLoginDate) {
305 response.data.user.lastLoginDate = new Date(
306 response.data.user.lastLoginDate
307 );
308 }
309 return response;
310 });
311});
312
313// use with apollo-client
314const link = addDatesLink.concat(httpLink);
315```