From f452a19e9a865c7f5e01b314fbdd191d9c0c2bf1 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Wed, 28 Oct 2020 13:27:32 +0000 Subject: [PATCH] Replace all remaining operation spreads with makeOperation --- docs/advanced/authentication.md | 50 ++++++++----------- docs/common-questions.md | 12 +++-- exchanges/auth/README.md | 10 ++-- exchanges/auth/src/authExchange.ts | 8 ++- exchanges/graphcache/src/offlineExchange.ts | 3 +- .../src/persistedFetchExchange.ts | 14 +++--- exchanges/populate/src/populateExchange.ts | 20 ++++---- .../src/requestPolicyExchange.ts | 13 ++--- exchanges/retry/src/retryExchange.ts | 10 ++-- packages/core/src/exchanges/cache.ts | 9 ++-- 10 files changed, 71 insertions(+), 78 deletions(-) diff --git a/docs/advanced/authentication.md b/docs/advanced/authentication.md index 38dfc325f4..49b3ef4e0c 100644 --- a/docs/advanced/authentication.md +++ b/docs/advanced/authentication.md @@ -82,7 +82,7 @@ const getAuth = async ({ authState }) => { } return null; -} +}; ``` We check that the `authState` doesn't already exist (this indicates that it is the first time this exchange is executed and not an auth failure) and fetch the auth state from @@ -104,7 +104,7 @@ const getAuth = async ({ authState, mutate }) => { } return null; -} +}; ``` ### Configuring `addAuthToOperation` @@ -113,10 +113,9 @@ The purpose of `addAuthToOperation` is to take apply your auth state to each req you've returned from `getAuth` and not at all constrained by the exchange: ```js -const addAuthToOperation = ({ - authState, - operation, -}) => { +import { makeOperation } from '@urql/core'; + +const addAuthToOperation = ({ authState, operation }) => { if (!authState || !authState.token) { return operation; } @@ -126,20 +125,17 @@ const addAuthToOperation = ({ ? operation.context.fetchOptions() : operation.context.fetchOptions || {}; - return { - ...operation, - context: { - ...operation.context, - fetchOptions: { - ...fetchOptions, - headers: { - ...fetchOptions.headers, - "Authorization": authState.token, - }, + return makeOperation(operation.kind, operation, { + ...operation.context, + fetchOptions: { + ...fetchOptions, + headers: { + ...fetchOptions.headers, + Authorization: authState.token, }, }, - }; -} + }); +}; ``` First we check that we have an `authState` and a `token`. Then we apply it to the request `fetchOptions` as an `Authorization` header. @@ -174,10 +170,8 @@ is the recommended approach. We'll be able to determine whether any of the Graph ```js const didAuthError = ({ error }) => { - return error.graphQLErrors.some( - e => e.extensions?.code === 'FORBIDDEN', - ); -} + return error.graphQLErrors.some(e => e.extensions?.code === 'FORBIDDEN'); +}; ``` For some GraphQL APIs, the auth error is communicated via an 401 HTTP response as is common in RESTful APIs: @@ -225,7 +219,7 @@ const getAuth = async ({ authState }) => { logout(); return null; -} +}; ``` Here, `logout()` is a placeholder that is called when we got an error, so that we can redirect to a login page again and clear our tokens from local storage or otherwise. @@ -299,14 +293,12 @@ const client = createClient({ cacheExchange, errorExchange({ onError: error => { - const isAuthError = error.graphQLErrors.some( - e => e.extensions?.code === 'FORBIDDEN', - ); + const isAuthError = error.graphQLErrors.some(e => e.extensions?.code === 'FORBIDDEN'); if (isAuthError) { logout(); } - } + }, }), authExchange({ /* config */ @@ -331,14 +323,14 @@ const App = ({ isLoggedIn }: { isLoggedIn: boolean | null }) => { if (isLoggedIn === null) { return null; } - + return createClient({ /* config */ }); }, [isLoggedIn]); if (!client) { return null; } - + return { {/* app content */} diff --git a/docs/common-questions.md b/docs/common-questions.md index 3b4c29b808..bb59211b69 100644 --- a/docs/common-questions.md +++ b/docs/common-questions.md @@ -10,6 +10,8 @@ order: 6 If you need `async fetchOptions` you can add an exchange that looks like this: ```js +import { makeOperation } from '@urql/core'; + export const fetchOptionsExchange = (fn: any): Exchange => ({ forward }) => ops$ => { return pipe( ops$, @@ -17,10 +19,12 @@ export const fetchOptionsExchange = (fn: any): Exchange => ({ forward }) => ops$ const result = fn(operation.context.fetchOptions); return pipe( typeof result.then === 'function' ? fromPromise(result) : fromValue(result), - map((fetchOptions: RequestInit | (() => RequestInit)) => ({ - ...operation, - context: { ...operation.context, fetchOptions }, - })) + map((fetchOptions: RequestInit | (() => RequestInit)) => { + return makeOperation(operation.kind, operation, { + ...operation.context, + fetchOptions, + }); + }) ); }), forward diff --git a/exchanges/auth/README.md b/exchanges/auth/README.md index b0bbea4bc0..c21f19832d 100644 --- a/exchanges/auth/README.md +++ b/exchanges/auth/README.md @@ -18,6 +18,7 @@ You'll then need to add the `authExchange`, that this package exposes to your `u ```js import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql'; +import { makeOperation } from '@urql/core'; import { authExchange } from '@urql/exchange-auth'; const client = createClient({ @@ -41,9 +42,10 @@ const client = createClient({ ? operation.context.fetchOptions() : operation.context.fetchOptions || {}; - return { - ...operation, - context: { + return makeOperation( + operation.kind, + operation, + { ...operation.context, fetchOptions: { ...fetchOptions, @@ -53,7 +55,7 @@ const client = createClient({ }, }, }, - }; + ); }, willAuthError: ({ authState }) => { if (!authState) return true; diff --git a/exchanges/auth/src/authExchange.ts b/exchanges/auth/src/authExchange.ts index 42c52aba3a..05a8a099fd 100644 --- a/exchanges/auth/src/authExchange.ts +++ b/exchanges/auth/src/authExchange.ts @@ -57,13 +57,11 @@ export interface AuthConfig { const addAuthAttemptToOperation = ( operation: Operation, hasAttempted: boolean -) => ({ - ...operation, - context: { +) => + makeOperation(operation.kind, operation, { ...operation.context, authAttempt: hasAttempted, - }, -}); + }); export function authExchange({ addAuthToOperation, diff --git a/exchanges/graphcache/src/offlineExchange.ts b/exchanges/graphcache/src/offlineExchange.ts index c9acc69213..a3596212a2 100644 --- a/exchanges/graphcache/src/offlineExchange.ts +++ b/exchanges/graphcache/src/offlineExchange.ts @@ -7,6 +7,7 @@ import { ExchangeIO, CombinedError, createRequest, + makeOperation, } from '@urql/core'; import { @@ -99,7 +100,7 @@ export const offlineExchange = (opts: CacheExchangeOpts): Exchange => input => { for (let i = 0; i < failedQueue.length; i++) { const operation = failedQueue[i]; if (operation.kind === 'mutation') { - next({ ...operation, operationName: 'teardown' }); + next(makeOperation('teardown', operation)); } } diff --git a/exchanges/persisted-fetch/src/persistedFetchExchange.ts b/exchanges/persisted-fetch/src/persistedFetchExchange.ts index 06bf8ac3c6..1ad95bb55d 100644 --- a/exchanges/persisted-fetch/src/persistedFetchExchange.ts +++ b/exchanges/persisted-fetch/src/persistedFetchExchange.ts @@ -13,6 +13,7 @@ import { } from 'wonka'; import { + makeOperation, CombinedError, ExchangeInput, Exchange, @@ -139,17 +140,16 @@ const makePersistedFetchSource = ( dispatchDebug: ExchangeInput['dispatchDebug'], useGet: boolean ): Source => { - const newOperation = { - ...operation, - context: { - ...operation.context, - preferGetMethod: useGet || operation.context.preferGetMethod, - }, - }; + const newOperation = makeOperation(operation.kind, operation, { + ...operation.context, + preferGetMethod: useGet || operation.context.preferGetMethod, + }); + const url = makeFetchURL( newOperation, body.query ? body : { ...body, query: '' } ); + const fetchOptions = makeFetchOptions(newOperation, body); dispatchDebug({ diff --git a/exchanges/populate/src/populateExchange.ts b/exchanges/populate/src/populateExchange.ts index 83d3c0d871..26009717ea 100644 --- a/exchanges/populate/src/populateExchange.ts +++ b/exchanges/populate/src/populateExchange.ts @@ -13,7 +13,7 @@ import { SelectionNode, } from 'graphql'; import { pipe, tap, map } from 'wonka'; -import { Exchange, Operation } from '@urql/core'; +import { makeOperation, Exchange, Operation } from '@urql/core'; import { warn } from './helpers/help'; import { @@ -61,15 +61,15 @@ export const populateExchange = ({ ); } - return { - ...op, - query: addFragmentsToQuery( - schema, - op.query, - activeSelections, - userFragments - ), - }; + const newOperation = makeOperation(op.kind, op); + newOperation.query = addFragmentsToQuery( + schema, + op.query, + activeSelections, + userFragments + ); + + return newOperation; }; /** Handle query and extract fragments. */ diff --git a/exchanges/request-policy/src/requestPolicyExchange.ts b/exchanges/request-policy/src/requestPolicyExchange.ts index 33bed8900f..7078fab0df 100644 --- a/exchanges/request-policy/src/requestPolicyExchange.ts +++ b/exchanges/request-policy/src/requestPolicyExchange.ts @@ -1,4 +1,4 @@ -import { Operation, Exchange } from '@urql/core'; +import { makeOperation, Operation, Exchange } from '@urql/core'; import { pipe, map } from 'wonka'; const defaultTTL = 5 * 60 * 1000; @@ -33,13 +33,10 @@ export const requestPolicyExchange = (options: Options): Exchange => ({ (options.shouldUpgrade ? options.shouldUpgrade(operation) : true) ) { operations.set(operation.key, new Date()); - return { - ...operation, - context: { - ...operation.context, - requestPolicy: 'cache-and-network', - }, - }; + return makeOperation(operation.kind, operation, { + ...operation.context, + requestPolicy: 'cache-and-network', + }); } return operation; diff --git a/exchanges/retry/src/retryExchange.ts b/exchanges/retry/src/retryExchange.ts index cfe7f0e2ea..3daf89eb83 100644 --- a/exchanges/retry/src/retryExchange.ts +++ b/exchanges/retry/src/retryExchange.ts @@ -10,6 +10,7 @@ import { takeUntil, } from 'wonka'; import { + makeOperation, Exchange, Operation, CombinedError, @@ -84,14 +85,13 @@ export const retryExchange = ({ // Add new retryDelay and retryCount to operation return pipe( - fromValue({ - ...op, - context: { + fromValue( + makeOperation(op.kind, op, { ...op.context, retryDelay: delayAmount, retryCount, - }, - }), + }) + ), delay(delayAmount), // Stop retry if a teardown comes in takeUntil(teardown$) diff --git a/packages/core/src/exchanges/cache.ts b/packages/core/src/exchanges/cache.ts index 6a448eb66d..a3328910b7 100755 --- a/packages/core/src/exchanges/cache.ts +++ b/packages/core/src/exchanges/cache.ts @@ -123,13 +123,12 @@ export const cacheExchange: Exchange = ({ forward, client, dispatchDebug }) => { // Reexecutes a given operation with the default requestPolicy const reexecuteOperation = (client: Client, operation: Operation) => { - return client.reexecuteOperation({ - ...operation, - context: { + return client.reexecuteOperation( + makeOperation(operation.kind, operation, { ...operation.context, requestPolicy: 'network-only', - }, - }); + }) + ); }; // Invalidates the cache given a mutation's response