Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 3.1 kB view raw
1/* eslint-disable @typescript-eslint/no-use-before-define */ 2import { filter, merge, mergeMap, pipe, takeUntil, onPush } from 'wonka'; 3 4import type { Exchange } from '../types'; 5import { 6 makeFetchBody, 7 makeFetchURL, 8 makeFetchOptions, 9 makeFetchSource, 10} from '../internal'; 11 12/** Default GraphQL over HTTP fetch exchange. 13 * 14 * @remarks 15 * The default fetch exchange in `urql` supports sending GraphQL over HTTP 16 * requests, can optionally send GraphQL queries as GET requests, and 17 * handles incremental multipart responses. 18 * 19 * This exchange does not handle persisted queries or multipart uploads. 20 * Support for the former can be added using `@urql/exchange-persisted-fetch` 21 * and the latter using `@urql/exchange-multipart-fetch`. 22 * 23 * Hint: The `fetchExchange` and the two other exchanges all use the built-in fetch 24 * utilities in `@urql/core/internal`, which you can also use to implement 25 * a customized fetch exchange. 26 * 27 * @see {@link makeFetchSource} for the shared utility calling the Fetch API. 28 */ 29export const fetchExchange: Exchange = ({ forward, dispatchDebug }) => { 30 return ops$ => { 31 const fetchResults$ = pipe( 32 ops$, 33 filter(operation => { 34 return ( 35 operation.kind !== 'teardown' && 36 (operation.kind !== 'subscription' || 37 !!operation.context.fetchSubscriptions) 38 ); 39 }), 40 mergeMap(operation => { 41 const body = makeFetchBody(operation); 42 const url = makeFetchURL(operation, body); 43 const fetchOptions = makeFetchOptions(operation, body); 44 45 dispatchDebug({ 46 type: 'fetchRequest', 47 message: 'A fetch request is being executed.', 48 operation, 49 data: { 50 url, 51 fetchOptions, 52 }, 53 }); 54 55 const source = pipe( 56 makeFetchSource(operation, url, fetchOptions), 57 takeUntil( 58 pipe( 59 ops$, 60 filter(op => op.kind === 'teardown' && op.key === operation.key) 61 ) 62 ) 63 ); 64 65 if (process.env.NODE_ENV !== 'production') { 66 return pipe( 67 source, 68 onPush(result => { 69 const error = !result.data ? result.error : undefined; 70 71 dispatchDebug({ 72 type: error ? 'fetchError' : 'fetchSuccess', 73 message: `A ${ 74 error ? 'failed' : 'successful' 75 } fetch response has been returned.`, 76 operation, 77 data: { 78 url, 79 fetchOptions, 80 value: error || result, 81 }, 82 }); 83 }) 84 ); 85 } 86 87 return source; 88 }) 89 ); 90 91 const forward$ = pipe( 92 ops$, 93 filter(operation => { 94 return ( 95 operation.kind === 'teardown' || 96 (operation.kind === 'subscription' && 97 !operation.context.fetchSubscriptions) 98 ); 99 }), 100 forward 101 ); 102 103 return merge([fetchResults$, forward$]); 104 }; 105};