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

fix(core): Allow path-only URLs to be used with GET requests (#3514)

authored by

Alexander Krantz and committed by
GitHub
eb1286c7 e9b476b6

+37 -4
+5
.changeset/curvy-sheep-drive.md
··· 1 + --- 2 + '@urql/core': patch 3 + --- 4 + 5 + Allow `url` to be a plain, non-URL pathname (i.e. `/api/graphql`) to be used with `preferGetMethod`
+20
packages/core/src/internal/fetchOptions.test.ts
··· 70 70 ); 71 71 }); 72 72 73 + it('returns the URL by default when only a path is provided', () => { 74 + const operation = makeOperation(queryOperation.kind, queryOperation, { 75 + url: '/graphql', 76 + }); 77 + const body = makeFetchBody(operation); 78 + expect(makeFetchURL(operation, body)).toBe('/graphql'); 79 + }); 80 + 73 81 it('returns a query parameter URL when GET is preferred', () => { 74 82 const operation = makeOperation(queryOperation.kind, queryOperation, { 75 83 ...queryOperation.context, ··· 79 87 const body = makeFetchBody(operation); 80 88 expect(makeFetchURL(operation, body)).toMatchInlineSnapshot( 81 89 '"http://localhost:3000/graphql?query=query+getUser%28%24name%3A+String%29+%7B%0A++user%28name%3A+%24name%29+%7B%0A++++id%0A++++firstName%0A++++lastName%0A++%7D%0A%7D&operationName=getUser&variables=%7B%22name%22%3A%22Clara%22%7D"' 90 + ); 91 + }); 92 + 93 + it('returns a query parameter URL when GET is preferred and only a path is provided', () => { 94 + const operation = makeOperation(queryOperation.kind, queryOperation, { 95 + url: '/graphql', 96 + preferGetMethod: true, 97 + }); 98 + 99 + const body = makeFetchBody(operation); 100 + expect(makeFetchURL(operation, body)).toMatchInlineSnapshot( 101 + '"/graphql?query=query+getUser%28%24name%3A+String%29+%7B%0A++user%28name%3A+%24name%29+%7B%0A++++id%0A++++firstName%0A++++lastName%0A++%7D%0A%7D&operationName=getUser&variables=%7B%22name%22%3A%22Clara%22%7D"' 82 102 ); 83 103 }); 84 104
+12 -4
packages/core/src/internal/fetchOptions.ts
··· 71 71 operation.kind === 'query' && operation.context.preferGetMethod; 72 72 if (!useGETMethod || !body) return operation.context.url; 73 73 74 - const url = new URL(operation.context.url); 74 + const urlParts = splitOutSearchParams(operation.context.url); 75 75 for (const key in body) { 76 76 const value = body[key]; 77 77 if (value) { 78 - url.searchParams.set( 78 + urlParts[1].set( 79 79 key, 80 80 typeof value === 'object' ? stringifyVariables(value) : value 81 81 ); 82 82 } 83 83 } 84 - 85 - const finalUrl = url.toString(); 84 + const finalUrl = urlParts.join('?'); 86 85 if (finalUrl.length > 2047 && useGETMethod !== 'force') { 87 86 operation.context.preferGetMethod = false; 88 87 return operation.context.url; 89 88 } 90 89 91 90 return finalUrl; 91 + }; 92 + 93 + const splitOutSearchParams = ( 94 + url: string 95 + ): readonly [string, URLSearchParams] => { 96 + const start = url.indexOf('?'); 97 + return start > -1 98 + ? [url.slice(0, start), new URLSearchParams(url.slice(start + 1))] 99 + : [url, new URLSearchParams()]; 92 100 }; 93 101 94 102 /** Serializes a {@link FetchBody} into a {@link RequestInit.body} format. */