From 8c7f1cc76aa5fa3dfb64be42ba513fa57aede8fe Mon Sep 17 00:00:00 2001 From: Maria Elisabeth Schreiber Date: Thu, 10 Aug 2023 13:52:48 -0600 Subject: [PATCH] Update persisted queries docs (#3160) Co-authored-by: Zach FettersMoore <4425109+BobaFetters@users.noreply.github.com> Co-authored-by: Alex Deem Co-authored-by: Jeff Auriemma Co-authored-by: Anthony Miller Co-authored-by: Martin Bonnin --- docs/source/_redirects | 1 + docs/source/config.json | 2 +- docs/source/fetching/apqs.mdx | 52 --------- docs/source/fetching/persisted-queries.mdx | 129 +++++++++++++++++++++ 4 files changed, 131 insertions(+), 53 deletions(-) delete mode 100644 docs/source/fetching/apqs.mdx create mode 100644 docs/source/fetching/persisted-queries.mdx diff --git a/docs/source/_redirects b/docs/source/_redirects index 8a28ecc857..330e15da72 100644 --- a/docs/source/_redirects +++ b/docs/source/_redirects @@ -2,3 +2,4 @@ /v1 /docs/ios/ /tutorial /docs/ios/tutorial/tutorial-introduction /tutorial/tutorial-create-project /docs/ios/tutorial/tutorial-add-sdk +/fetching/apqs /docs/ios/fetching/persisted-queries diff --git a/docs/source/config.json b/docs/source/config.json index 6baaa5fb89..94118a4739 100644 --- a/docs/source/config.json +++ b/docs/source/config.json @@ -78,7 +78,7 @@ "Error Handling": "/fetching/error-handling", "Type Conditions": "/fetching/type-conditions", "Custom Scalars": "/custom-scalars", - "Automatic Persisted Queries": "/fetching/apqs" + "Persisted Queries": "/fetching/persisted-queries" }, true ], diff --git a/docs/source/fetching/apqs.mdx b/docs/source/fetching/apqs.mdx deleted file mode 100644 index 68c12bd08f..0000000000 --- a/docs/source/fetching/apqs.mdx +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Automatic Persisted Queries ---- - -Apollo Server allows you to use a feature called [Automatic Persisted Queries](https://www.apollographql.com/docs/apollo-server/performance/apq/), or APQs, to avoiding sending the same large query documents over and over. - -> **Note:** APQs are an Apollo Server feature. They are not part of the GraphQL specification, and are only available when using Apollo iOS with an Apollo Server instance that has APQs enabled. - -Each query or mutation is identified by the SHA256 hash of its contents. If the hash can't be found by the server, it sends back an error indicating that it needs the full query. If it receives this specific error, Apollo iOS will automatically retry the operation with the full query document without you having to do anything. - -> **Note:** APQs are not supported over Websockets at this time. If you're interested in this feature, please open an [issue](https://github.com/apollographql/apollo-ios/issues/new/choose)! - -## Using APQs with Apollo iOS - -To enable APQs you must configure code generation and your `ApolloClient` correctly. - -### 1. Configure code generation to APQ compatible operations - -In order to use APQs, your operations must have SHA256 hash identifiers included in the generated operation objects. To configure code generation to include these identifiers, set the `ApolloCodegenConfiguration`'s `options.apqs` to `.automaticallyPersist`. - -To set this property in your `apollo-codegen-config.json` file, add set the `options.apqs` property in the JSON to `"automaticallyPersist"`: -```json title="apollo-codegen-config.json" -"options" { - "apqs": "automaticallyPersist" -} - ``` - -### 2. Enable APQs on your `ApolloClient` - -You must also initialize your `ApolloClient`, with a custom `NetworkTransport` that supports APQs. - -Initialize a `RequestChainNetworkTransport` with `autoPersistQueries` parameter set to `true` and an `interceptorProvider` that includes the `AutomaticPersistedQueryInterceptor` (such as `DefaultInterceptorProvider`). - -```swift -let store = ApolloStore(cache: InMemoryNormalizedCache()) -let interceptorProvider = DefaultInterceptorProvider(store: store) -let networkTransport = RequestChainNetworkTransport( - interceptorProvider: interceptorProvider, - endpointURL: URL(string: "http://localhost:4000/graphql")! -) - -let client = ApolloClient(networkTransport: networkTransport, store: store) -``` -For more information on configuring your `ApolloClient`, `NetworkTransport`, `InterceptorProvider`, and the request chain, see the [Request Pipeline](./../networking/request-pipeline) documentation. - -## Send APQs as `GET` requests - -By default, retries of queries will use `POST`. In some cases, it may be required or preferred to retry persisted operation using a `GET` request (for example, when your queries are hitting a CDN that has better performance with `GET`). - -In order to use `GET` for persisted query retry requests, set the `useGETForPersistedQueryRetry` on your `RequestChainNetworkTransport` to `true`. - -Most users will want to leave this option as `false`. diff --git a/docs/source/fetching/persisted-queries.mdx b/docs/source/fetching/persisted-queries.mdx new file mode 100644 index 0000000000..358340e711 --- /dev/null +++ b/docs/source/fetching/persisted-queries.mdx @@ -0,0 +1,129 @@ +--- +title: Persisted Queries +description: Secure your graph while minimizing request latency +--- + + + +## Differences between persisted queries and APQ + + + +## Implementation steps + +Both persisted queries and APQs require you to configure code generation and how your client makes requests. If you intend to use persisted queries for safelisting, you also need to generate an operations manifest. + +We recommend you follow this order while implementing: + +| Implementation Step | Required for PQs? | Required for APQs? | +| -----| ------------------ | ----------------- | +| 1. Configure generated operation models| ✅ | ✅ | +| 2. Generate the operation manifest |✅ | -- | +| 3. Publish the operation manifest |✅ | -- | +| 4. Enable persisted queries on the client when it makes requests | ✅ | ✅ | + +The rest of this article details these steps. + +Persisted queries also require you to create and link a PQL, and to configure your router to receive persisted query requests. This document only describes the steps that need to be taken by the client to create a manifest of the client's operations and send persisted query requests. For more information on the other configuration aspects of persisted queries, see the [GraphOS persisted queries documentation](/graphos/operations/persisted-queries). + +### 0. Requirements + +You can use APQ with the following versions of Apollo iOS, Apollo Server, and Apollo Router: +- Apollo iOS (v1.0.0+) +- [Apollo Server](/apollo-server/) (v1.0.0+) +- [Apollo Router](/router) (v0.1.0+) + +> **Note:** You can use _either_ Apollo Server _or_ Apollo Router for APQs. They don't need to be used together. + +Persisted queries is currently in [preview](/resources/product-launch-stages#preview) and has the following requirements: +- Apollo iOS (v1.4.0+) +- [Apollo Router](/router) (v1.25.0+) +- [GraphOS Enterprise plan](/graphos/enterprise/) + +### 1. Configure generated operation models + +Both persisted queries and APQs require your code generation to include operation IDs. You can configure this in your code generation configuration's [`options`](output-options). +Specifically, set the `operationDocumentFormat` array to `definition`, `operationId`, or both `definition` and `operationId`. +- To use APQs, you must include both the `definition` and `operationId`. +- For persisted queries, you only need the `operationId`. + +```json title="apollo-codegen-config.json" +"options": { + "operationDocumentFormat" : [ + "definition", + "operationId" + ] +} +``` + +### 2. Generate operation manifest + +> This step is only required for implementing safelisting with persisted queries. It is _not_ required for APQs. + +An operation manifest acts as a safelist of trusted operations the [Apollo Router](/router/) can check incoming requests against. You can generate operation manifests by adding the [`operationManifest`](./../code-generation/codegen-configuration#operation-manifest-configuration) option to your `ApolloCodegenConfiguration` JSON file like so: + +```json title="apollo-codegen-config.json" +"operationManifest" : { + "generateManifestOnCodeGeneration" : false, + "path" : "/operation/identifiers/path", + "version" : "persistedQueries" +} +``` + +Once these options are configured you can run the [`generate-operation-manifest`](./../code-generation/codegen-cli#generate-operation-manifest) in order to generate your operation manifest. If you have the `generateManifestOnCodeGeneration` flag set to `true` your operation manifest will also generate everytime you run the [`generate`](./../code-generation/codegen-cli#generate) command. + +The resulting operation manifest for `persistedQueries` looks like this: + +```json title="operationIdentifiers.json" +{ + "format": "apollo-persisted-query-manifest", + "version": 1, + "operations": [ + { + "id": "e0321f6b438bb42c022f633d38c19549dea9a2d55c908f64c5c6cb8403442fef", + "body": "query GetItem { thing { __typename } }", + "name": "GetItem", + "type": "query" + } + ] +} +``` + +To automatically update the manifest for each new app release, you can include the [`generate`](./../code-generation/codegen-cli#generate) or [`generate-operation-manifest`](./../code-generation/codegen-cli#generate-operation-manifest) command in your CI/CD pipeline. + +### 3. Publish operation manifest + +> This step is only required for implementing safelisting with persisted queries. It is _not_ required for APQs. + + + +### 4. Enable persisted queries on `ApolloClient` + +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 APQ or persisted queries: + +- Initialize a custom `NetworkTransport` using `RequestChainNetworkTransport` with `autoPersistQueries` parameter set to `true` and an `interceptorProvider` that includes the `AutomaticPersistedQueryInterceptor` (such as `DefaultInterceptorProvider`). +- Initialize your `ApolloClient` with the custom `NetworkTransport` that supports persisted queries. + +```swift +let store = ApolloStore(cache: InMemoryNormalizedCache()) +let interceptorProvider = DefaultInterceptorProvider(store: store) +let networkTransport = RequestChainNetworkTransport( + interceptorProvider: interceptorProvider, + endpointURL: URL(string: "http://localhost:4000/graphql")!, + autoPersistQueries: true +) + +let client = ApolloClient(networkTransport: networkTransport, store: store) +``` + +For more information on configuring your `ApolloClient`, `NetworkTransport`, `InterceptorProvider`, and the request chain, see the [request pipeline](./../networking/request-pipeline) documentation. + +#### Sending APQ retries as `GET` requests + +> **Note:** Apollo iOS only retries failed ID-based operations for APQs, not persisted queries. + +By default, the Apollo clients sends operation retries as `POST` requests. In some cases, you may prefer or need to retry an operation using a `GET` request: for example, you may make requests to a CDN that has better performance with `GET`s. + +To use `GET` for APQ retry requests, set the `useGETForPersistedQueryRetry` on your `RequestChainNetworkTransport` to `true`. + +In most cases, keeping the default option (`false`) suffices. \ No newline at end of file