|
1 | 1 | ---
|
2 |
| -title: Persisted queries |
3 |
| -description: Secure your graph while minimizing request latency |
| 2 | +title: Persisted queries in Apollo Kotlin |
4 | 3 | ---
|
5 | 4 |
|
6 |
| -<ClientPQIntro /> |
| 5 | +## Automatic persisted queries |
7 | 6 |
|
8 |
| -Hashed queries are also sent by default using HTTP `GET` instead of the default `POST`, making them easier to cache in your edge network. |
| 7 | +Apollo Kotlin supports [Automatic Persisted Queries](https://www.apollographql.com/docs/apollo-server/performance/apq/) (APQ). To take advantage of it, your GraphQL server _also_ needs to support APQ (Apollo Server supports it out of the box). |
9 | 8 |
|
10 |
| -## Differences between persisted queries and APQs |
11 |
| - |
12 |
| -<ClientPQDifferences /> |
13 |
| - |
14 |
| -## Implementation steps |
15 |
| - |
16 |
| -Both persisted queries and APQs require you to configure how your client makes requests. If you intend to use persisted queries for safelisting, you also need to generate and publish an operation manifest. |
17 |
| - |
18 |
| -<ClientPQImplementation /> |
19 |
| - |
20 |
| -### 0. Requirements |
21 |
| - |
22 |
| -You can use APQs with the following versions of Apollo Kotlin, Apollo Server, and Apollo Router: |
23 |
| -- Apollo Kotlin (v1.0.0+) |
24 |
| -- [Apollo Server](/apollo-server/) (v1.0.0+) |
25 |
| -- [Apollo Router](/router) (v0.1.0+) |
26 |
| - |
27 |
| -> **Note:** You can use _either_ Apollo Server _or_ Apollo Router for APQs. They don't need to be used together. |
28 |
| -
|
29 |
| -Persisted queries is currently in [preview](/resources/product-launch-stages#preview) and has the following requirements: |
30 |
| -- Apollo Kotlin (v3.8.2+) |
31 |
| -- [Apollo Router](/router) (v1.25.0+) |
32 |
| -- [GraphOS Enterprise plan](/graphos/enterprise/) |
33 |
| - |
34 |
| -### 1. Generate operation manifest |
35 |
| - |
36 |
| -> This step is only required for implementing safelisting with persisted queries. It is _not_ required for APQs. |
37 |
| -
|
38 |
| -The operation manifest acts as a safelist of trusted operations the [Apollo Router](/router/) can check incoming requests against. |
39 |
| -To generate the operation manifest, set `operationManifestFormat` to `"persistedQueryManifest"` in your Gradle script: |
| 9 | +Enable the feature when you initialize your `ApolloClient` instance, like so: |
40 | 10 |
|
41 | 11 | ```kotlin
|
42 |
| -// build.gradle.kts |
43 |
| -apollo { |
44 |
| - service("api") { |
45 |
| - packageName.set("com.example") |
46 |
| - |
47 |
| - // Enable generation of the operation manifest |
48 |
| - operationManifestFormat.set("persistedQueryManifest") // highlight-line |
49 |
| - } |
50 |
| -} |
| 12 | +val apolloClient = ApolloClient.Builder() |
| 13 | + .serverUrl("https://...") |
| 14 | + .autoPersistedQueries() |
| 15 | + .build() |
51 | 16 | ```
|
52 | 17 |
|
53 |
| -The operation manifest is generated during code generation. This happens automatically every time you build your project or you can trigger it manually by executing the `generateApolloSources` Gradle task. |
54 |
| - |
55 |
| -The operation manifest is generated in `build/generated/manifest/apollo/$serviceName/persistedQueryManifest.json`, where `$serviceName` is `"api"` here. The resulting operation manifest looks something like this: |
56 |
| - |
57 |
| -```json title="persistedQueryManifest.json" |
58 |
| -{ |
59 |
| - "format": "apollo-persisted-query-manifest", |
60 |
| - "version": 1, |
61 |
| - "operations": [ |
62 |
| - { |
63 |
| - "id": "e0321f6b438bb42c022f633d38c19549dea9a2d55c908f64c5c6cb8403442fef", |
64 |
| - "body": "query GetItem { thing { __typename } }", |
65 |
| - "name": "GetItem", |
66 |
| - "type": "query" |
67 |
| - } |
68 |
| - ] |
69 |
| -} |
| 18 | +You can optionally configure the HTTP methods to use. Using `GET` may take advantage of HTTP caching for instance when using a CDN: |
| 19 | +```kotlin |
| 20 | +val apolloClient = ApolloClient.Builder() |
| 21 | + .serverUrl("https://...") |
| 22 | + .autoPersistedQueries( |
| 23 | + // For the initial hashed query that does not send the actual Graphql document |
| 24 | + httpMethodForHashedQueries = HttpMethod.Get, |
| 25 | + |
| 26 | + // For the follow-up query that sends the full document if the initial hashed query was not found |
| 27 | + httpMethodForDocumentQueries = HttpMethod.Get |
| 28 | + ) |
| 29 | + .build() |
70 | 30 | ```
|
71 | 31 |
|
72 |
| -### 2. Publish operation manifest |
| 32 | +Note that mutations will always be sent as `POST` requests, regardless of these settings, as to avoid hitting caches. |
73 | 33 |
|
74 |
| -> This step is only required for implementing safelisting with persisted queries. It is _not_ required for APQs. |
75 |
| -
|
76 |
| -<PublishPQMs /> |
77 |
| - |
78 |
| -### 3. Enable persisted queries on `ApolloClient` |
79 |
| - |
80 |
| -Once you've configured your code generation to include operation IDs, you can update your client to query by operation ID rather than the full operation string. This configuration is the same whether you're using APQs or persisted queries. Call `autoPersistedQueries()` on your `ApolloClient.Builder`: |
| 34 | +## Disable persisted queries for certain queries |
81 | 35 |
|
| 36 | +You may want to disable persisted queries for certain queries, for instance to avoid any caching when the data is updated often. In order to do that, set `enableAutoPersistedQueries` to false on the `ApolloCall`: |
82 | 37 | ```kotlin
|
83 |
| -val apolloClient = ApolloClient.Builder() |
84 |
| - .serverUrl("https://...") |
85 |
| - .autoPersistedQueries() |
86 |
| - .build() |
| 38 | +apolloClient.query(myQuery).enableAutoPersistedQueries(false).toFlow() |
87 | 39 | ```
|
88 | 40 |
|
89 |
| -Once APQs are enabled on your ApolloClient, hashed queries are sent by default. |
| 41 | +## operationOutput.json |
90 | 42 |
|
91 |
| -You may want to disable automatic persisted queries for certain queries, for instance to avoid any caching when the data is updated often. To do that, set `enableAutoPersistedQueries` to false on the `ApolloCall`: |
| 43 | +If your backend uses custom persisted queries, Apollo Kotlin can generate an OperationOutput json from your .graphql queries. They will match what the client is sending exactly so you can persist them on your server. |
92 | 44 |
|
93 | 45 | ```kotlin
|
94 |
| -apolloClient.query(myQuery).enableAutoPersistedQueries(false).toFlow() |
| 46 | +apollo { |
| 47 | + service("service") { |
| 48 | + generateOperationOutput.set(true) |
| 49 | + } |
| 50 | +} |
95 | 51 | ```
|
96 | 52 |
|
97 |
| -## Generating custom IDs for persisted queries |
| 53 | +## Custom ID for Persisted Queries |
98 | 54 |
|
99 |
| -By default, Apollo uses `Sha256` hashing algorithm to generate an ID for the query. To provide custom ID generation logic, use the `operationIdGenerator` option. It accepts an `instance` that implements the `OperationIdGenerator` interface (`com.apollographql.apollo3.compiler.OperationIdGenerator`) as the input. You can use this option to either specify a different hashing algorithm or to fetch the persisted query ID from a different location, for example, from a service or a CLI. |
| 55 | +By default, Apollo uses `Sha256` hashing algorithm to generate an ID for the query. To provide custom ID generation logic, use the option - `operationIdGenerator` which accepts an `instance` that implements the `OperationIdGenerator` interface (`com.apollographql.apollo3.compiler.OperationIdGenerator`) as the input. This option can be used to either specify a different hashing algorithm or to fetch the persisted query ID from a different place - e.g. a service or a CLI. |
100 | 56 |
|
101 | 57 | Example Md5 hash generator:
|
102 | 58 |
|
@@ -138,6 +94,6 @@ apollo {
|
138 | 94 |
|
139 | 95 | </MultiCodeBlock>
|
140 | 96 |
|
141 |
| -### ID generator versioning |
| 97 | +### Versioning Id Generator |
142 | 98 |
|
143 | 99 | The result of the ID generator is cached. The cache is not updated when the implementation of the ID Generator changes. To indicate an update to the implementation of the ID Generator, change the `version` override as shown in the above example.
|
0 commit comments