For a project that I'm working on we're making use of the GET method to make the call benefit of HTTP caching. This is working successfully but we do notice that the query parameter contains characters which are not necessary for executing the query.
Example
Below an example were we are using graphql-tag
to parse the query. Newlines are included for readability of the query.
import gql from 'graphql-tag';
const HERO_QUERY = gql`
query HERO_QUERY {
hero {
name
friends {
name
}
}
}
`;
The actual behaviour results in the following HTTP request:
GET /graphql?query=query%20HERO_QUERY%20%7B%0A%20%20hero%20%7B%0A%20%20%20%20name%0A%20%20%20%20friends%20%7B%0A%20%20%20%20%20%20name%0A%20%20%20%20%20%20__typename%0A%20%20%20%20%7D%0A%20%20%20%20__typename%0A%20%20%7D%0A%7D%0A&operationName=HERO_QUERY&variables=%7B%7D HTTP/1.1
Host: localhost:3000
Connection: keep-alive
content-type: application/json
Expected behaviour is a GET query without unnecessary characters:
GET /graphql?query=query%20HERO_QUERY%7Bhero%7Bname%20friends%7Bname%7D%7D%7D&operationName=HERO_QUERY&variables=%7B%7D HTTP/1.1
Host: localhost:3000
Connection: keep-alive
content-type: application/json
I currently don't directly see a way/ability to implement a workaround to achieve the same result. If this request make sense I can provide a PR for this to do the necessary modifications.
The body of rewriteURIForGET
can be stripped before going through the encodeURIComponent
.
It would be possible to reuse the logic that is used in graphql
package where there is a utility method available stripIgnoredCharacters.
The package graphql
is already referenced in apollo-link-http
and can be reused or custom logic can be directly included to sanitize the query.
I’ve tried to do the modification outside the apollo-link-http
library by creating a custom ApolloLink
extension to strip the query before it gets passed towards createHttpLink
but with no luck unfortunately.
import { ApolloLink } from 'apollo-link';
import gql from 'graphql-tag';
import { print } from 'graphql/language/printer';
import { stripIgnoredCharacters } from 'graphql/utilities/stripIgnoredCharacters';
class CreateShortQueryLink extends ApolloLink {
request(operation, forward) {
const strippedQuery = stripIgnoredCharacters(print(operation.query));
const request = {
...operation,
getContext: operation.getContext,
setContext: operation.setContext,
query: gql(strippedQuery),
};
return forward(request);
}
}
const link = ApolloLink.from([
new CreateShortQueryLink(),
createHttpLink({ uri: 'http://localhost:3000/graphql' }),
]);
It seems that the print
of graphql/language/printer
is adding again the unnecessary characters.
print(gql('query Posts{posts(orderBy:id_DESC){id title __typename}}'))
// outputs
query Posts{posts(orderBy:id_DESC){id title __typename}} query Posts {
posts(orderBy: id_DESC) {
id
title
__typename
}
}
This same method print
method seems to be also used by apollo-link-http-common
which is used in apollo-link-http
to create the GET query.
Also tried the above with something like:
export const createMinifyLink = () => {
return new ApolloLink((operation: Operation, forward: NextLink) => {
const stripped = stripIgnoredCharacters(operation.query.loc!.source);
return forward({
...operation,
getContext: operation.getContext,
setContext: operation.setContext,
query: gql(stripped),
});
});
};
But get a load of warnings about re-using fragment names and problems writing to store.
I would use an HTTP Interceptor but then you've got issues with differing hashes when using APQ. I've got queries that are 44kb and full of %20%20%20
. Think if I can strip the ignored characters it'd probably half the size.
You can't even pre-process it because ApolloClient just adds __typename throughout and re-prettifies it:
export function stripIgnoredCharactersGql(literals: string[], ...placeholders: any[]) {
const strippedLiterals = literals.map(str => stripIgnoredCharacters(str));
return gql(strippedLiterals, ...placeholders);
}
export const configQuery = stripIgnoredCharactersGql`
query {
hello {
world
}
}
`;
We've ended up patching apollo-link-http-common via https://www.npmjs.com/package/patch-package to use stripIgnoredCharacters right after printer was used:
patches/apollo-link-http-common+0.2.13.patch
diff --git a/node_modules/apollo-link-http-common/lib/index.js b/node_modules/apollo-link-http-common/lib/index.js
index 05cd095..c79da1b 100644
--- a/node_modules/apollo-link-http-common/lib/index.js
+++ b/node_modules/apollo-link-http-common/lib/index.js
@@ -2,6 +2,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var printer_1 = require("graphql/language/printer");
+var utilities_1 = require("graphql/utilities/stripIgnoredCharacters");
var ts_invariant_1 = require("ts-invariant");
var defaultHttpOptions = {
includeQuery: true,
@@ -91,6 +92,7 @@ exports.selectHttpOptionsAndBody = function (operation, fallbackConfig) {
body.extensions = extensions;
if (http.includeQuery)
body.query = printer_1.print(query);
+ body.query = utilities_1.stripIgnoredCharacters(body.query);
return {
options: options,
body: body,
Most helpful comment
We've ended up patching apollo-link-http-common via https://www.npmjs.com/package/patch-package to use stripIgnoredCharacters right after printer was used:
patches/apollo-link-http-common+0.2.13.patch