Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

implement conversion for useHTTPGetForQueries (#519)

* implement conversion for useHTTPGetForQueries

* add tests

* correct tests

* assume query will be present

* conver to preferGetMethod

* run prettier

* update snapshots

* move to context

* cast to boolean

* update client tests

authored by

Jovi De Croock and committed by
GitHub
14a31ed8 748ab3ea

+78 -5
+1
src/__snapshots__/client.test.ts.snap
··· 13 13 "fetch": undefined, 14 14 "fetchOptions": undefined, 15 15 "operations$": [Function], 16 + "preferGetMethod": false, 16 17 "reexecuteOperation": [Function], 17 18 "requestPolicy": "cache-first", 18 19 "results$": [Function],
+4
src/__snapshots__/context.test.ts.snap
··· 26 26 "fetch": undefined, 27 27 "fetchOptions": undefined, 28 28 "operations$": [Function], 29 + "preferGetMethod": false, 29 30 "reexecuteOperation": [Function], 30 31 "requestPolicy": "cache-first", 31 32 "results$": [Function], ··· 44 45 "fetch": undefined, 45 46 "fetchOptions": undefined, 46 47 "operations$": [Function], 48 + "preferGetMethod": false, 47 49 "reexecuteOperation": [Function], 48 50 "requestPolicy": "cache-first", 49 51 "results$": [Function], ··· 81 83 "fetch": undefined, 82 84 "fetchOptions": undefined, 83 85 "operations$": [Function], 86 + "preferGetMethod": false, 84 87 "reexecuteOperation": [Function], 85 88 "requestPolicy": "cache-first", 86 89 "results$": [Function], ··· 99 102 "fetch": undefined, 100 103 "fetchOptions": undefined, 101 104 "operations$": [Function], 105 + "preferGetMethod": false, 102 106 "reexecuteOperation": [Function], 103 107 "requestPolicy": "cache-first", 104 108 "results$": [Function],
+2
src/client.test.ts
··· 91 91 fetchOptions: undefined, 92 92 fetch: undefined, 93 93 suspense: false, 94 + preferGetMethod: false, 94 95 }); 95 96 expect(queryResult).toHaveProperty('then'); 96 97 }); ··· 119 120 requestPolicy: 'cache-and-network', 120 121 fetchOptions: undefined, 121 122 fetch: undefined, 123 + preferGetMethod: false, 122 124 }); 123 125 expect(mutationResult).toHaveProperty('then'); 124 126 });
+6
src/client.ts
··· 66 66 suspense?: boolean; 67 67 /** The default request policy for requests. */ 68 68 requestPolicy?: RequestPolicy; 69 + /** Use HTTP GET for queries. */ 70 + preferGetMethod?: boolean; 69 71 } 70 72 71 73 interface ActiveOperations { ··· 82 84 fetchOptions?: RequestInit | (() => RequestInit); 83 85 exchange: Exchange; 84 86 suspense: boolean; 87 + preferGetMethod: boolean; 85 88 requestPolicy: RequestPolicy; 86 89 87 90 // These are internals to be used to keep track of operations ··· 94 97 if (process.env.NODE_ENV !== 'production' && !opts.url) { 95 98 throw new Error('You are creating an urql-client without a url.'); 96 99 } 100 + 97 101 this.url = opts.url; 98 102 this.fetchOptions = opts.fetchOptions; 99 103 this.fetch = opts.fetch; 100 104 this.suspense = !!opts.suspense; 101 105 this.requestPolicy = opts.requestPolicy || 'cache-first'; 106 + this.preferGetMethod = !!opts.preferGetMethod; 102 107 103 108 // This subject forms the input of operations; executeOperation may be 104 109 // called to dispatch a new operation on the subject ··· 152 157 url: this.url, 153 158 fetchOptions: this.fetchOptions, 154 159 fetch: this.fetch, 160 + preferGetMethod: this.preferGetMethod, 155 161 ...opts, 156 162 requestPolicy: (opts || {}).requestPolicy || this.requestPolicy, 157 163 });
+37 -1
src/exchanges/fetch.test.ts
··· 2 2 import { Client } from '../client'; 3 3 import { queryOperation } from '../test-utils'; 4 4 import { OperationResult, OperationType } from '../types'; 5 - import { fetchExchange } from './fetch'; 5 + import { fetchExchange, convertToGet } from './fetch'; 6 + import gql from 'graphql-tag'; 6 7 7 8 const fetch = (global as any).fetch as jest.Mock; 8 9 const abort = jest.fn(); ··· 151 152 expect(abort).toHaveBeenCalledTimes(0); 152 153 }); 153 154 }); 155 + 156 + describe('convert for GET', () => { 157 + it('should do a basic conversion', () => { 158 + const query = `query ($id: ID!) { node(id: $id) { id } }`; 159 + const variables = { id: 2 }; 160 + expect(convertToGet('http://localhost:3000', { query, variables })).toBe( 161 + `http://localhost:3000?query=${encodeURIComponent( 162 + query 163 + )}&variables=${encodeURIComponent(JSON.stringify(variables))}` 164 + ); 165 + }); 166 + 167 + it('should do a basic conversion with fragments', () => { 168 + const nodeFragment = gql` 169 + fragment nodeFragment on Node { 170 + id 171 + } 172 + `; 173 + const variables = { id: 2 }; 174 + const query = gql` 175 + query($id: ID!) { 176 + node(id: $id) { 177 + ...nodeFragment 178 + } 179 + } 180 + ${nodeFragment} 181 + `; 182 + 183 + expect(convertToGet('http://localhost:3000', { query, variables })).toBe( 184 + `http://localhost:3000?query=${encodeURIComponent( 185 + query 186 + )}&variables=${encodeURIComponent(JSON.stringify(variables))}` 187 + ); 188 + }); 189 + });
+27 -4
src/exchanges/fetch.ts
··· 29 29 filter(op => op.operationName === 'teardown' && op.key === key) 30 30 ); 31 31 32 - return pipe(createFetchSource(operation), takeUntil(teardown$)); 32 + return pipe( 33 + createFetchSource( 34 + operation, 35 + operation.operationName === 'query' && 36 + !!operation.context.preferGetMethod 37 + ), 38 + takeUntil(teardown$) 39 + ); 33 40 }) 34 41 ); 35 42 ··· 53 60 return node !== undefined && node.name ? node.name.value : null; 54 61 }; 55 62 56 - const createFetchSource = (operation: Operation) => { 63 + const createFetchSource = (operation: Operation, shouldUseGet: boolean) => { 57 64 if ( 58 65 process.env.NODE_ENV !== 'production' && 59 66 operation.operationName === 'subscription' ··· 88 95 } 89 96 90 97 const fetchOptions = { 91 - body: JSON.stringify(body), 92 - method: 'POST', 93 98 ...extraOptions, 99 + body: shouldUseGet ? undefined : JSON.stringify(body), 100 + method: shouldUseGet ? 'GET' : 'POST', 94 101 headers: { 95 102 'content-type': 'application/json', 96 103 ...extraOptions.headers, ··· 99 106 abortController !== undefined ? abortController.signal : undefined, 100 107 }; 101 108 109 + if (shouldUseGet) { 110 + operation.context.url = convertToGet(operation.context.url, body); 111 + } 112 + 102 113 let ended = false; 103 114 104 115 Promise.resolve() ··· 146 157 } 147 158 }); 148 159 }; 160 + 161 + export const convertToGet = (uri: string, body: Body): string => { 162 + const queryParams: string[] = [`query=${encodeURIComponent(body.query)}`]; 163 + 164 + if (body.variables) { 165 + queryParams.push( 166 + `variables=${encodeURIComponent(JSON.stringify(body.variables))}` 167 + ); 168 + } 169 + 170 + return uri + '?' + queryParams.join('&'); 171 + };
+1
src/types.ts
··· 50 50 pollInterval?: number; 51 51 meta?: OperationDebugMeta; 52 52 suspense?: boolean; 53 + preferGetMethod?: boolean; 53 54 } 54 55 55 56 /** A [query]{@link Query} or [mutation]{@link Mutation} with additional metadata for use during transmission. */