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.

(persisted-fetch) - Fix hash not being sent after Not Found error (#766)

* Fix persisted query miss not sending SHA256 hash

* Add changeset

authored by

Phil Plückthun and committed by
GitHub
d2c78bfa 7f711391

+52 -73
+5
.changeset/little-years-cough.md
··· 1 + --- 2 + '@urql/exchange-persisted-fetch': patch 3 + --- 4 + 5 + Fix `persistedFetchExchange` not sending the SHA256 hash extension after a cache miss (`PersistedQueryNotFound` error)
+1 -1
exchanges/persisted-fetch/src/__snapshots__/persistedFetchExchange.test.ts.snap
··· 4 4 5 5 exports[`supports cache-miss persisted query errors 1`] = `"{\\"operationName\\":\\"getUser\\",\\"variables\\":{\\"name\\":\\"Clara\\"},\\"extensions\\":{\\"persistedQuery\\":{\\"version\\":1,\\"sha256Hash\\":\\"bfa84414672fe625d36f2d2a52e1d3c1e71c5a01e79599c320db7656d6f014d4\\"}}}"`; 6 6 7 - exports[`supports cache-miss persisted query errors 2`] = `"{\\"query\\":\\"query getUser($name: String) {\\\\n user(name: $name) {\\\\n id\\\\n firstName\\\\n lastName\\\\n }\\\\n}\\\\n\\",\\"operationName\\":\\"getUser\\",\\"variables\\":{\\"name\\":\\"Clara\\"}}"`; 7 + exports[`supports cache-miss persisted query errors 2`] = `"{\\"query\\":\\"query getUser($name: String) {\\\\n user(name: $name) {\\\\n id\\\\n firstName\\\\n lastName\\\\n }\\\\n}\\\\n\\",\\"operationName\\":\\"getUser\\",\\"variables\\":{\\"name\\":\\"Clara\\"},\\"extensions\\":{\\"persistedQuery\\":{\\"version\\":1,\\"sha256Hash\\":\\"bfa84414672fe625d36f2d2a52e1d3c1e71c5a01e79599c320db7656d6f014d4\\"}}}"`; 8 8 9 9 exports[`supports unsupported persisted query errors 1`] = `"{\\"operationName\\":\\"getUser\\",\\"variables\\":{\\"name\\":\\"Clara\\"},\\"extensions\\":{\\"persistedQuery\\":{\\"version\\":1,\\"sha256Hash\\":\\"bfa84414672fe625d36f2d2a52e1d3c1e71c5a01e79599c320db7656d6f014d4\\"}}}"`;
+46 -72
exchanges/persisted-fetch/src/persistedFetchExchange.ts
··· 21 21 } from '@urql/core'; 22 22 23 23 import { 24 + FetchBody, 24 25 makeFetchBody, 25 26 makeFetchURL, 26 27 makeFetchOptions, ··· 47 48 filter(op => op.operationName === 'teardown' && op.key === key) 48 49 ); 49 50 51 + const body = makeFetchBody(operation); 50 52 if (!supportsPersistedQueries) { 53 + // Runs the usual non-persisted fetchExchange query logic 51 54 return pipe( 52 - makeNormalFetchSource(operation, dispatchDebug), 55 + makePersistedFetchSource(operation, body, dispatchDebug), 53 56 takeUntil(teardown$) 54 57 ); 55 58 } 56 59 60 + const query: string = body.query!; 61 + 57 62 return pipe( 58 - makePersistedFetchSource(operation, dispatchDebug), 63 + // Hash the given GraphQL query 64 + fromPromise(hash(query)), 65 + mergeMap(sha256Hash => { 66 + // Attach SHA256 hash and remove query from body 67 + body.query = undefined; 68 + body.extensions = { 69 + persistedQuery: { 70 + version: 1, 71 + sha256Hash, 72 + }, 73 + }; 74 + 75 + return makePersistedFetchSource(operation, body, dispatchDebug); 76 + }), 59 77 mergeMap(result => { 60 78 if (result.error && isPersistedUnsupported(result.error)) { 79 + // Reset the body back to its non-persisted state 80 + body.query = query; 81 + body.extensions = undefined; 82 + // Disable future persisted queries 61 83 supportsPersistedQueries = false; 62 - return makeNormalFetchSource(operation, dispatchDebug); 84 + return makePersistedFetchSource(operation, body, dispatchDebug); 63 85 } else if (result.error && isPersistedMiss(result.error)) { 64 - return makeNormalFetchSource(operation, dispatchDebug); 86 + // Add query to the body but leave SHA256 hash intact 87 + body.query = query; 88 + return makePersistedFetchSource(operation, body, dispatchDebug); 65 89 } 66 90 67 91 return fromValue(result); ··· 83 107 84 108 const makePersistedFetchSource = ( 85 109 operation: Operation, 110 + body: FetchBody, 86 111 dispatchDebug: ExchangeInput['dispatchDebug'] 87 112 ): Source<OperationResult> => { 88 - const body = makeFetchBody(operation); 89 - const query: string = body.query!; 90 - 91 - return pipe( 92 - fromPromise(hash(query)), 93 - mergeMap(sha256Hash => { 94 - body.query = undefined; 95 - body.extensions = { 96 - persistedQuery: { 97 - version: 1, 98 - sha256Hash, 99 - }, 100 - }; 101 - 102 - const url = makeFetchURL(operation, { ...body, query: '' }); 103 - const fetchOptions = makeFetchOptions(operation, body); 104 - 105 - dispatchDebug({ 106 - type: 'fetchRequest', 107 - message: 'A fetch request for a persisted query is being executed.', 108 - operation, 109 - data: { 110 - url, 111 - fetchOptions, 112 - }, 113 - }); 114 - 115 - return pipe( 116 - makeFetchSource(operation, url, fetchOptions), 117 - onPush(result => { 118 - const persistFail = 119 - result.error && 120 - (isPersistedMiss(result.error) || 121 - isPersistedUnsupported(result.error)); 122 - const error = !result.data ? result.error : undefined; 123 - 124 - dispatchDebug({ 125 - // TODO: Assign a new name to this once @urql/devtools supports it 126 - type: persistFail || error ? 'fetchError' : 'fetchSuccess', 127 - message: persistFail 128 - ? 'A Persisted Query request has failed. A non-persisted GraphQL request will follow.' 129 - : `A ${ 130 - error ? 'failed' : 'successful' 131 - } fetch response has been returned.`, 132 - operation, 133 - data: { 134 - url, 135 - fetchOptions, 136 - value: persistFail ? result.error! : error || result, 137 - }, 138 - }); 139 - }) 140 - ); 141 - }) 113 + const url = makeFetchURL( 114 + operation, 115 + body.query ? body : { ...body, query: '' } 142 116 ); 143 - }; 144 - 145 - const makeNormalFetchSource = ( 146 - operation: Operation, 147 - dispatchDebug: ExchangeInput['dispatchDebug'] 148 - ): Source<OperationResult> => { 149 - const body = makeFetchBody(operation); 150 - const url = makeFetchURL(operation, body); 151 117 const fetchOptions = makeFetchOptions(operation, body); 152 118 153 119 dispatchDebug({ 154 120 type: 'fetchRequest', 155 - message: 'A fetch request is being executed.', 121 + message: !body.query 122 + ? 'A fetch request for a persisted query is being executed.' 123 + : 'A fetch request is being executed.', 156 124 operation, 157 125 data: { 158 126 url, ··· 163 131 return pipe( 164 132 makeFetchSource(operation, url, fetchOptions), 165 133 onPush(result => { 134 + const persistFail = 135 + result.error && 136 + (isPersistedMiss(result.error) || isPersistedUnsupported(result.error)); 166 137 const error = !result.data ? result.error : undefined; 167 138 168 139 dispatchDebug({ 169 - type: error ? 'fetchError' : 'fetchSuccess', 170 - message: `A ${ 171 - error ? 'failed' : 'successful' 172 - } fetch response has been returned.`, 140 + // TODO: Assign a new name to this once @urql/devtools supports it 141 + type: persistFail || error ? 'fetchError' : 'fetchSuccess', 142 + message: persistFail 143 + ? 'A Persisted Query request has failed. A non-persisted GraphQL request will follow.' 144 + : `A ${ 145 + error ? 'failed' : 'successful' 146 + } fetch response has been returned.`, 173 147 operation, 174 148 data: { 175 149 url, 176 150 fetchOptions, 177 - value: error || result, 151 + value: persistFail ? result.error! : error || result, 178 152 }, 179 153 }); 180 154 })