From 77fe7725d039f89500f03560aea19254630d8a5f Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 3 Feb 2021 23:07:24 +0000 Subject: [PATCH] (persisted) - Add enforcePersistedQueries option to persistedFetchExchange (#1358) --- .changeset/cuddly-squids-cheat.md | 5 ++ docs/advanced/persistence-and-uploads.md | 5 ++ docs/api/persisted-fetch-exchange.md | 1 + exchanges/persisted-fetch/README.md | 5 +- .../src/persistedFetchExchange.ts | 52 ++++++++++--------- 5 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 .changeset/cuddly-squids-cheat.md diff --git a/.changeset/cuddly-squids-cheat.md b/.changeset/cuddly-squids-cheat.md new file mode 100644 index 0000000000..69ee898508 --- /dev/null +++ b/.changeset/cuddly-squids-cheat.md @@ -0,0 +1,5 @@ +--- +'@urql/exchange-persisted-fetch': minor +--- + +Add `enforcePersistedQueries` option to `persistedFetchExchange`, which disables automatic persisted queries and retry logic, and instead assumes that persisted queries will be handled like normal GraphQL requests. diff --git a/docs/advanced/persistence-and-uploads.md b/docs/advanced/persistence-and-uploads.md index f28a81218c..6f9c71f145 100644 --- a/docs/advanced/persistence-and-uploads.md +++ b/docs/advanced/persistence-and-uploads.md @@ -107,6 +107,11 @@ persistedFetchExchange({ }); ``` +Additionally, if the API only expects persisted queries and not arbitrary ones and all queries are +pre-registered against the API then the `persistedFetchExchange` may be put into a **non-automatic** +persisted queries mode by giving it the `enforcePersistedQueries: true` option. This disables any +retry logic and assumes that persisted queries will be handled like regular GraphQL requests. + [Read more about `@urql/persisted-fetch-exchange` in our API docs.](../api/persisted-fetch-exchange.md) diff --git a/docs/api/persisted-fetch-exchange.md b/docs/api/persisted-fetch-exchange.md index 28c33ef6de..7be8161fda 100644 --- a/docs/api/persisted-fetch-exchange.md +++ b/docs/api/persisted-fetch-exchange.md @@ -63,4 +63,5 @@ const client = createClient({ | Option | Description | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `preferGetForPersistedQueries` | This is similar to [the `Client`'s `preferGetMethod` option](./core.md#client) and will cause all persisted queries to be sent using a GET request. | +| `enforcePersistedQueries` | This option enforced persisted queries. Instead of allowing automatic persisted queries or triggering any retry logic when the API responds, it instead assumes that persisted queries will succeed and run like normal GraphQL API requests. | | `generateHash` | This option accepts a function that receives the `query` as a string and the raw `DocumentNode` as a second argument and must return a `Promise` resolving to a SHA256 hash. This can be used to swap out the SHA256 API, e.g. for React Native, or to use pre-generated SHA256 strings from the `DocumentNode`. | diff --git a/exchanges/persisted-fetch/README.md b/exchanges/persisted-fetch/README.md index edc1ba9269..e17435ce8a 100644 --- a/exchanges/persisted-fetch/README.md +++ b/exchanges/persisted-fetch/README.md @@ -33,9 +33,12 @@ const client = createClient({ }); ``` -The `persistedQueryExchange` supports two configuration options: +The `persistedQueryExchange` supports three configuration options: - `preferGetForPersistedQueries`: Use `GET` for fetches with persisted queries +- `enforcePersistedQueries`: This disables _automatic persisted queries_ and disables any retry + logic for how the API responds to persisted queries. Instead it's assumed that they'll always + succeed. - `generateHash`: A function that takes a GraphQL query and returns the hashed result. This defaults to the `window.crypto` API in the browser and the `crypto` module in node. The `persistedFetchExchange` only handles queries, so for mutations we keep the diff --git a/exchanges/persisted-fetch/src/persistedFetchExchange.ts b/exchanges/persisted-fetch/src/persistedFetchExchange.ts index 1ad95bb55d..3acc526cfe 100644 --- a/exchanges/persisted-fetch/src/persistedFetchExchange.ts +++ b/exchanges/persisted-fetch/src/persistedFetchExchange.ts @@ -34,6 +34,7 @@ import { hash } from './sha256'; interface PersistedFetchExchangeOptions { preferGetForPersistedQueries?: boolean; + enforcePersistedQueries?: boolean; generateHash?: (query: string, document: DocumentNode) => Promise; } @@ -42,6 +43,8 @@ export const persistedFetchExchange = ( ): Exchange => ({ forward, dispatchDebug }) => { if (!options) options = {}; + const preferGetForPersistedQueries = !!options.preferGetForPersistedQueries; + const enforcePersistedQueries = !!options.enforcePersistedQueries; const hashFn = options.generateHash || hash; let supportsPersistedQueries = true; @@ -87,34 +90,33 @@ export const persistedFetchExchange = ( operation, body, dispatchDebug, - !!( - (options as PersistedFetchExchangeOptions) - .preferGetForPersistedQueries && sha256Hash - ) + !!(preferGetForPersistedQueries && sha256Hash) ); }), mergeMap(result => { - if (result.error && isPersistedUnsupported(result.error)) { - // Reset the body back to its non-persisted state - body.query = query; - body.extensions = undefined; - // Disable future persisted queries - supportsPersistedQueries = false; - return makePersistedFetchSource( - operation, - body, - dispatchDebug, - false - ); - } else if (result.error && isPersistedMiss(result.error)) { - // Add query to the body but leave SHA256 hash intact - body.query = query; - return makePersistedFetchSource( - operation, - body, - dispatchDebug, - false - ); + if (!enforcePersistedQueries) { + if (result.error && isPersistedUnsupported(result.error)) { + // Reset the body back to its non-persisted state + body.query = query; + body.extensions = undefined; + // Disable future persisted queries if they're not enforced + supportsPersistedQueries = false; + return makePersistedFetchSource( + operation, + body, + dispatchDebug, + false + ); + } else if (result.error && isPersistedMiss(result.error)) { + // Add query to the body but leave SHA256 hash intact + body.query = query; + return makePersistedFetchSource( + operation, + body, + dispatchDebug, + false + ); + } } return fromValue(result);