Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 2.8 kB view raw
1import type { Exchange, Operation, OperationContext } from '@urql/core'; 2import { makeOperation } from '@urql/core'; 3 4import { fromPromise, fromValue, mergeMap, pipe } from 'wonka'; 5 6/** Input parameters for the {@link contextExchange}. */ 7export interface ContextExchangeArgs { 8 /** Returns a new {@link OperationContext}, optionally wrapped in a `Promise`. 9 * 10 * @remarks 11 * `getContext` is called for every {@link Operation} the `contextExchange` 12 * receives and must return a new {@link OperationContext} or a `Promise` 13 * of it. 14 * 15 * The new `OperationContext` will be used to update the `Operation`'s 16 * context before it's forwarded to the next exchange. 17 */ 18 getContext( 19 operation: Operation 20 ): OperationContext | Promise<OperationContext>; 21} 22 23/** Exchange factory modifying the {@link OperationContext} per incoming `Operation`. 24 * 25 * @param options - A {@link ContextExchangeArgs} configuration object. 26 * @returns the created context {@link Exchange}. 27 * 28 * @remarks 29 * The `contextExchange` allows the {@link OperationContext` to be easily 30 * modified per `Operation`. This may be useful to dynamically change the 31 * `Operation`’s parameters, even when we need to do so asynchronously. 32 * 33 * You must define a {@link ContextExchangeArgs.getContext} function, 34 * which may return a `Promise<OperationContext>` or `OperationContext`. 35 * 36 * Hint: If the `getContext` function passed to this exchange returns a 37 * `Promise` it must be placed _after_ all synchronous exchanges, such as 38 * a `cacheExchange`. 39 * 40 * @example 41 * ```ts 42 * import { Client, cacheExchange, fetchExchange } from '@urql/core'; 43 * import { contextExchange } from '@urql/exchange-context'; 44 * 45 * const client = new Client({ 46 * url: '', 47 * exchanges: [ 48 * cacheExchange, 49 * contextExchange({ 50 * async getContext(operation) { 51 * const url = await loadDynamicUrl(); 52 * return { 53 * ...operation.context, 54 * url, 55 * }; 56 * }, 57 * }), 58 * fetchExchange, 59 * ], 60 * }); 61 * ``` 62 */ 63 64export const contextExchange = 65 ({ getContext }: ContextExchangeArgs): Exchange => 66 ({ forward }) => { 67 return ops$ => { 68 return pipe( 69 ops$, 70 mergeMap(operation => { 71 const result = getContext(operation); 72 const isPromise = 'then' in result; 73 if (isPromise) { 74 return fromPromise( 75 result.then((ctx: OperationContext) => 76 makeOperation(operation.kind, operation, ctx) 77 ) 78 ); 79 } else { 80 return fromValue( 81 makeOperation( 82 operation.kind, 83 operation, 84 result as OperationContext 85 ) 86 ); 87 } 88 }), 89 forward 90 ); 91 }; 92 };