You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
description: Improve network performance by sending smaller requests
4
4
---
5
5
6
-
The size of individual GraphQL query strings can be a major pain point. Apollo Server implements Automatic Persisted Queries (APQ), a technique that greatly improves network performance for GraphQL with zero build-time configuration. A persisted query is an ID or hash that can be sent to the server instead of the entire GraphQL query string. This smaller signature reduces bandwidth utilization and speeds up client loading times. Persisted queries are especially nice paired with `GET` requests, enabling the browser cache and [integration with a CDN](#using-get-requests-with-apq-on-a-cdn).
6
+
Clients send queries to Apollo Server as HTTP requests that include the GraphQL string of the query to execute. Depending on your graph's schema, the size of a valid query string might be arbitrarily large. As query strings become larger, increased latency and network usage can noticeably degrade client performance.
7
+
8
+
To improve network performance for large query strings, Apollo Server supports **Automatic Persisted Queries** (**APQ**). A persisted query is a query string that's stored on the server side, along with its unique identifier (always its SHA-256 hash). Clients can send this identifier _instead of_ the corresponding query string, thus reducing request sizes dramatically (response sizes are unaffected).
9
+
10
+
To persist a query string, Apollo Server must first receive it from a requesting client. Consequently, the _first_ execution of each unique query does _not_ benefit from APQ.
11
+
12
+
```mermaid
13
+
sequenceDiagram;
14
+
Client app->>Apollo Server: Sends SHA-256 hash of query string to execute
15
+
Note over Apollo Server: Fails to find persisted query string
16
+
Apollo Server->>Client app: Responds with error
17
+
Client app->>Apollo Server: Sends both query string AND hash
18
+
Note over Apollo Server: Persists query string and hash
19
+
Apollo Server->>Client app: Executes query and returns result
20
+
Note over Client app: Time passes
21
+
Client app->>Apollo Server: Sends SHA-256 hash of query string to execute
22
+
Note over Apollo Server: Finds persisted query string
23
+
Apollo Server->>Client app: Executes query and returns result
24
+
```
25
+
26
+
Persisted queries are especially effective when clients send queries as `GET` requests. This enables clients to take advantage of the browser cache and [integrate with a CDN](#using-get-requests-with-apq-on-a-cdn).
27
+
28
+
Because query identifiers are deterministic hashes, clients can generate them at runtime. No additional build steps are required.
29
+
30
+
## Apollo Client setup
31
+
32
+
Apollo Server supports APQ without any additional configuration. However, some _client-side_ configuration is required.
7
33
8
-
With Automatic Persisted Queries, the ID is a deterministic hash of the input query, so we don't need a complex build step to share the ID between clients and servers. If a server doesn't know about a given hash, the client can expand the query for it; Apollo Server caches that mapping.
34
+
To set up APQ in Apollo Client, first import the `createPersistedQueryLink` function in the same file where you initialize `ApolloClient`:
Apollo Server supports automatic persisted queries without any additional configuration and only requires changes to Apollo Client.
40
+
This function creates a link that you can add to your client's [Apollo Link chain](https://www.apollographql.com/docs/react/api/link/introduction/). The link takes care of generating APQ identifiers, using `GET` requests for hashed queries, and retrying requests with query strings when necessary.
13
41
14
-
To get started with APQ, add the [Automatic Persisted Queries Link](https://github.com/apollographql/apollo-link-persisted-queries) to the **client** codebase with `npm install apollo-link-persisted-queries`. Next incorporate the APQ link with Apollo Client's link chain before the HTTP link:
42
+
Add the persisted query link anywhere in the chain before the terminating link. This example shows a basic two-link chain:
> Note: Users of `apollo-boost` should [migrate to `apollo-client`](https://www.apollographql.com/docs/react/advanced/boost-migration/) in order to use the `apollo-link-persisted-queries` package.
56
+
## Command-line testing
31
57
32
-
## Verify
58
+
You can test out APQ directly from the command line. This section also helps illustrate the shape of APQ requests, so you can use it to add APQ support to GraphQL clients besides Apollo Client.
33
59
34
-
Apollo Server's persisted queries configuration can be tested from the command-line. The following examples assume Apollo Server is running at `localhost:4000/`.
35
-
This example persists a dummy query of `{__typename}`, using its sha256 hash: `ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38`.
60
+
> This section assumes your server is running locally at `http://localhost:4000/graphql`.
36
61
62
+
Almost every GraphQL server supports the following query (which requests the `__typename` field from the `Query` type):
Expect a response of `{"data": {"__typename": "Query"}}"`.
80
+
The first time you try this, Apollo Server responds with an error with the code `PERSISTED_QUERY_NOT_FOUND`. This tells us that Apollo Server hasn't yet received the associated query string.
53
81
54
-
3. Request the persisted query again:
82
+
2. Send a followup request that includes both the query string _and_ its hash, like so:
Expect a response of `{"data": {"__typename": "Query"}}"`, as the query string is loaded from the cache.
88
+
This time, the server persists the query string and then responds with the query result as we'd expect.
61
89
62
-
## Using `GET` requests with APQ on a CDN
90
+
> The hash you provide _must_ be the exact SHA-256 hash of the query string. If it isn't, Apollo Server returns an error.
63
91
64
-
A great application for APQ is running Apollo Server behind a CDN. Many CDNs only cache GET requests, but many GraphQL queries are too long to fit comfortably in a cacheable GET request. When the APQ link is created with `createPersistedQueryLink({useGETForHashedQueries: true})`, Apollo Client automatically sends the short hashed queries as GET requests allowing a CDN to serve those request. For full-length queries and for all mutations, Apollo Client will continue to use POST requests.
92
+
3. Finally, attempt the request from step 1 again:
The mechanism is based on a lightweight protocol extension between Apollo Client and Apollo Server. It works as follows:
98
+
This time, the server responds with the query result because it successfully located the associated query string in its cache.
69
99
70
-
- When the client makes a query, it will optimistically send a short (64-byte) cryptographic hash instead of the full query text.
71
-
-**Optimized Path:** If a request containing a persisted query hash is detected, Apollo Server will look it up to find a corresponding query in its registry. Upon finding a match, Apollo Server will expand the request with the full text of the query and execute it.
-**New Query Path:** In the unlikely event that the query is not already in the Apollo Server registry (this only happens the very first time that Apollo Server sees a query), it will ask the client to resend the request using the full text of the query. At that point, Apollo Server will store the query / hash mapping in the registry for all subsequent requests to benefit from.
A great application for APQ is running Apollo Server behind a CDN. Many CDNs only cache GET requests, but many GraphQL queries are too long to fit comfortably in a cacheable GET request. When the APQ link is created with `createPersistedQueryLink({useGETForHashedQueries: true})`, Apollo Client automatically sends the short hashed queries as GET requests allowing a CDN to serve those request. For full-length queries and for all mutations, Apollo Client will continue to use POST requests.
78
103
79
104
## CDN Integration
80
105
@@ -138,7 +163,7 @@ const client = new ApolloClient({
138
163
});
139
164
```
140
165
141
-
> If you are testing locally, make sure to include the full [URI](https://developer.mozilla.org/en-US/docs/Glossary/URI) including the port number. For example: ` uri: "http://localhost:4000/graphql"`.
166
+
> If you are testing locally, make sure to include the full [URI](https://developer.mozilla.org/en-US/docs/Glossary/URI) including the port number. For example: ` uri: "http://localhost:4000/graphql"`.
142
167
143
168
Make sure to include `useGETForHashedQueries: true`. Note that the client will still use POSTs for mutations because it's generally best to avoid GETs for non-idempotent requests.
0 commit comments