|
1 | | -# batched-graphql-request [](https://travis-ci.org/graphcool/graphql-request) [](https://badge.fury.io/js/graphql-request) [](https://greenkeeper.io/) |
| 1 | +# http-link-dataloader |
2 | 2 |
|
3 | | -📚📡 Node-only, batched version of the graphql-request library |
| 3 | +A Apollo Link that batches requests both in Node and the Browser. |
| 4 | +You may ask what's the difference to [apollo-link-batch-http](https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-batch-http). |
| 5 | +Instead of having a time-frame/fixed cache size based batching approach like in `apollo-link-batch-http`, this library uses [dataloader](https://github.com/facebook/dataloader) for batching requests. It is a more generic approach just depending on the Node.JS event loop that batches all consecutive queries directly. |
| 6 | +The main use-case for this library is the usage from a [`graphql-yoga`](https://github.com/graphcool/graphql-yoga) server using [`prisma-binding`](https://github.com/graphcool/prisma-binding), but it can be used in any environment, even the browser as the latest `dataloader` version also runs in browser environments. |
4 | 7 |
|
5 | | -## Features |
| 8 | +## Usage |
6 | 9 |
|
7 | | -* Most **simple and lightweight** GraphQL client |
8 | | -* Includes batching and caching based [`dataloader`](https://github.com/facebook/dataloader) |
9 | | -* Promise-based API (works with `async` / `await`) |
10 | | -* Typescript support (Flow coming soon) |
| 10 | +```ts |
| 11 | +import { BatchedHTTPLink } from 'http-link-dataloader' |
11 | 12 |
|
12 | | -## Idea |
13 | | -The idea of this library is to provide query batching and caching for Node.js backends on a per-request basis. |
14 | | -That means, per http request to your Node.js backend, you create a new instance of `BatchedGraphQLClient` which has its |
15 | | -own cache and batching. Sharing a `BatchedGraphQLClient` instance across requests against your webserver is not recommended as that would result |
16 | | -in Memory Leaks with the Cache growing infinitely. The batching and caching is based on [`dataloader`](https://github.com/facebook/dataloader) |
| 13 | +const link = new BatchedHTTPLink() |
17 | 14 |
|
18 | | -## Install |
| 15 | +const token = 'Auth Token' |
19 | 16 |
|
20 | | -```sh |
21 | | -npm install batched-graphql-request |
| 17 | +const httpLink = new BatchedHttpLink({ |
| 18 | + uri: `api endpoint`, |
| 19 | + headers: { Authorization: `Bearer ${token}` }, |
| 20 | +}) |
22 | 21 | ``` |
23 | 22 |
|
24 | | -## Usage |
25 | | -The basic usage is exactly the same as you're used to with [`graphql-request`](https://github.com/graphcool/graphql-request) |
26 | | -```js |
27 | | -import { BatchedGraphQLClient } from 'batched-graphql-request' |
| 23 | +## Caching behavior |
| 24 | + |
| 25 | +Note that the dataloader cache aggressively caches everything! That means if you don't want to cache anymore, just create a new instance of `BatchedHTTPLink`. |
| 26 | +A good fit for this is every incoming HTTP request in a server environment - on each new HTTP request a new `BatchedHTTPLink` instance is created. |
| 27 | + |
| 28 | +## Batching |
| 29 | + |
| 30 | +This library uses array-based batching. Querying 2 queries like this creates the following payload: |
| 31 | + |
| 32 | +```graphql |
| 33 | +query { |
| 34 | + Item(id: "1") { |
| 35 | + id |
| 36 | + name |
| 37 | + text |
| 38 | + } |
| 39 | +} |
| 40 | +``` |
28 | 41 |
|
29 | | -const client = new BatchedGraphQLClient(endpoint, { headers: {} }) |
30 | | -client.request(query, variables).then(data => console.log(data)) |
| 42 | +```graphql |
| 43 | +query { |
| 44 | + Item(id: "2") { |
| 45 | + id |
| 46 | + name |
| 47 | + text |
| 48 | + } |
| 49 | +} |
31 | 50 | ``` |
32 | 51 |
|
33 | | -## Examples |
| 52 | +Instead of sending 2 separate http requests, it gets combined into one: |
34 | 53 |
|
35 | | -### Creating a new Client per request |
36 | | -In this example, we proxy requests that come in the form of [batched array](https://blog.graph.cool/improving-performance-with-apollo-query-batching-66455ea9d8bc). |
37 | | -Instead of sending each request individually to `my-endpoint`, all requests are again batched together and send grouped to |
38 | | -the underlying endpoint, which increases the performance dramatically. |
39 | 54 | ```js |
40 | | -import { BatchedGraphQLClient } from 'batched-graphql-request' |
41 | | -import * as express from 'express' |
42 | | -import * as bodyParser from 'body-parser' |
43 | | - |
44 | | -const app = express() |
45 | | - |
46 | | -/* |
47 | | -This accepts POST requests to /graphql of this form: |
48 | | -[ |
49 | | - {query: "...", variables: {}}, |
50 | | - {query: "...", variables: {}}, |
51 | | - {query: "...", variables: {}} |
| 55 | +;[ |
| 56 | + { |
| 57 | + query: `query { |
| 58 | + Item(id: "1") { |
| 59 | + id |
| 60 | + name |
| 61 | + text |
| 62 | + } |
| 63 | + }`, |
| 64 | + }, |
| 65 | + { |
| 66 | + query: `query { |
| 67 | + Item(id: "2") { |
| 68 | + id |
| 69 | + name |
| 70 | + text |
| 71 | + } |
| 72 | + }`, |
| 73 | + }, |
52 | 74 | ] |
53 | | - */ |
54 | | - |
55 | | -app.use( |
56 | | - '/graphql', |
57 | | - bodyParser.json(), |
58 | | - async (req, res) => { |
59 | | - const client = new BatchedGraphQLClient('my-endpoint', { |
60 | | - headers: { |
61 | | - Authorization: 'Bearer my-jwt-token', |
62 | | - }, |
63 | | - }) |
64 | | - |
65 | | - const requests = Array.isArray(req.body) ? req.body : [req.body] |
66 | | - |
67 | | - const results = await Promise.all(requests.map(({query, variables}) => client.request(query, variables))) |
68 | | - |
69 | | - res.json(results) |
70 | | - } |
71 | | -) |
| 75 | +``` |
72 | 76 |
|
73 | | -app.listen(3000, () => |
74 | | - console.log('Server running.'), |
75 | | -) |
| 77 | +**Note that the GraphQL Server needs to support the array-based batching!** |
| 78 | +(Prisma supports this out of the box) |
| 79 | + |
| 80 | +## Even better batching |
| 81 | + |
| 82 | +A batching that would even be faster is alias-based batching. Instead of creating the array described above, it would generate something like this: |
| 83 | + |
| 84 | +```js |
| 85 | + { |
| 86 | + query: ` |
| 87 | + query { |
| 88 | + item_1: Item(id: "1") { |
| 89 | + id |
| 90 | + name |
| 91 | + text |
| 92 | + } |
| 93 | + item_2: Item(id: "2") { |
| 94 | + id |
| 95 | + name |
| 96 | + text |
| 97 | + } |
| 98 | + }` |
| 99 | + }, |
76 | 100 | ``` |
77 | 101 |
|
78 | | -To learn more about the usage, please check out [graphql-request](https://github.com/graphcool/graphql-request) |
| 102 | +This requires a lot more logic and resolution logic for aliases, but would be a lot faster than the array based batching! |
| 103 | +Anyone intersted in working on this is more than welcome to do so! |
| 104 | +You can either create an issue or just reach out to us in slack and join our #contributors channel. |
79 | 105 |
|
80 | 106 | ## Help & Community [](https://slack.graph.cool) |
81 | 107 |
|
|
0 commit comments