Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 4.1 kB view raw
1import { mergeMap, fromValue, fromPromise, pipe } from 'wonka'; 2import type { Operation, OperationResult, Exchange } from '../types'; 3import type { CombinedError } from '../utils'; 4 5/** Options for the `mapExchange` allowing it to react to incoming operations, results, or errors. */ 6export interface MapExchangeOpts { 7 /** Accepts a callback for incoming `Operation`s. 8 * 9 * @param operation - An {@link Operation} that the {@link mapExchange} received. 10 * @returns optionally a new {@link Operation} replacing the original. 11 * 12 * @remarks 13 * You may return new {@link Operation | Operations} from this function replacing 14 * the original that the {@link mapExchange} received. 15 * It’s recommended that you use the {@link makeOperation} utility to create a copy 16 * of the original when you do this. (However, this isn’t required) 17 * 18 * Hint: The callback may also be promisified and return a new {@link Operation} asynchronously, 19 * provided you place your {@link mapExchange} after all synchronous {@link Exchange | Exchanges}, 20 * like after your `cacheExchange`. 21 */ 22 onOperation?(operation: Operation): Promise<Operation> | Operation | void; 23 /** Accepts a callback for incoming `OperationResult`s. 24 * 25 * @param result - An {@link OperationResult} that the {@link mapExchange} received. 26 * @returns optionally a new {@link OperationResult} replacing the original. 27 * 28 * @remarks 29 * This callback may optionally return a new {@link OperationResult} that replaces the original, 30 * which you can use to modify incoming API results. 31 * 32 * Hint: The callback may also be promisified and return a new {@link Operation} asynchronously, 33 * provided you place your {@link mapExchange} after all synchronous {@link Exchange | Exchanges}, 34 * like after your `cacheExchange`. 35 */ 36 onResult?( 37 result: OperationResult 38 ): Promise<OperationResult> | OperationResult | void; 39 /** Accepts a callback for incoming `CombinedError`s. 40 * 41 * @param error - A {@link CombinedError} that an incoming {@link OperationResult} contained. 42 * @param operation - The {@link Operation} of the incoming {@link OperationResult}. 43 * 44 * @remarks 45 * The callback may also be promisified and return a new {@link Operation} asynchronously, 46 * provided you place your {@link mapExchange} after all synchronous {@link Exchange | Exchanges}, 47 * like after your `cacheExchange`. 48 */ 49 onError?(error: CombinedError, operation: Operation): void; 50} 51 52/** Creates an `Exchange` mapping over incoming operations, results, and/or errors. 53 * 54 * @param opts - A {@link MapExchangeOpts} configuration object, containing the callbacks the `mapExchange` will use. 55 * @returns the created {@link Exchange} 56 * 57 * @remarks 58 * The `mapExchange` may be used to react to or modify incoming {@link Operation | Operations} 59 * and {@link OperationResult | OperationResults}. Optionally, it can also modify these 60 * asynchronously, when a promise is returned from the callbacks. 61 * 62 * This is useful to, for instance, add an authentication token to a given request, when 63 * the `@urql/exchange-auth` package would be overkill. 64 * 65 * It can also accept an `onError` callback, which can be used to react to incoming 66 * {@link CombinedError | CombinedErrors} on results, and trigger side-effects. 67 * 68 */ 69export const mapExchange = ({ 70 onOperation, 71 onResult, 72 onError, 73}: MapExchangeOpts): Exchange => { 74 return ({ forward }) => 75 ops$ => { 76 return pipe( 77 pipe( 78 ops$, 79 mergeMap(operation => { 80 const newOperation = 81 (onOperation && onOperation(operation)) || operation; 82 return 'then' in newOperation 83 ? fromPromise(newOperation) 84 : fromValue(newOperation); 85 }) 86 ), 87 forward, 88 mergeMap(result => { 89 if (onError && result.error) onError(result.error, result.operation); 90 const newResult = (onResult && onResult(result)) || result; 91 return 'then' in newResult 92 ? fromPromise(newResult) 93 : fromValue(newResult); 94 }) 95 ); 96 }; 97};