Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] apollo-link-http GET method remove ignored characters #1079

Open
SaschaDens opened this issue Jun 10, 2019 · 3 comments
Open

[Feature] apollo-link-http GET method remove ignored characters #1079

SaschaDens opened this issue Jun 10, 2019 · 3 comments

Comments

@SaschaDens
Copy link

@SaschaDens SaschaDens commented Jun 10, 2019

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.

function rewriteURIForGET(chosenURI: string, body: Body) {
// Implement the standard HTTP GET serialization, plus 'extensions'. Note
// the extra level of JSON serialization!
const queryParams = [];
const addQueryParam = (key: string, value: string) => {
queryParams.push(`${key}=${encodeURIComponent(value)}`);

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.

@SaschaDens

This comment has been minimized.

Copy link
Author

@SaschaDens SaschaDens commented Jun 24, 2019

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.

if (http.includeQuery) (body as any).query = print(query);

@intellix

This comment has been minimized.

Copy link

@intellix intellix commented Aug 12, 2019

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
    }
  }
`;
@biomancer

This comment has been minimized.

Copy link

@biomancer biomancer commented Oct 9, 2019

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,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.