0

I am currently using the Apollo GraphQl client - which sends POST requests by default - and would like to switch to using the GET request version to enable caching the response.

However quite a few requests are failing to fetch because the GET query that is sent ends up larger than 8kb.

I have constructed the queries in a way where there is 1 query per endpoint and have applied the concept of "withables" to opt into extra fields on demand. e.g.

// example query

{
  query(
    id: int,
    withFieldA?: boolean,
    withFieldB?: boolean
  ) {
    the_endpoint(id: $id, withFieldA: $withFieldA, withFieldB: $withFieldB) {
      id
      title
      
      field_a @include(id: withFieldA) {
        id
        // more values
      }

      
      field_b @include(id: withFieldB) {
        id
        // more values
      }

      // etc
    }
  }
}
// example usage

import query from 'queries/the_endpoint.gql'

apolloClient.query({ query, variables: { id: 1, withFieldA: true } })

So the problem is that while what's being requested is generally pretty small, the size of the query being sent across the network is massive because all the withables that haven't been opted into are also being included.

What I would like to do is make the query as lean as possible and only include the fields that have been opted into before sending the query across the network.

Is there a way to scrub the query before sending it?

Thanks

devdev
  • 11
  • 1
  • 2

1 Answers1

0

Solved with the help of the graphql visitor tool.

import { visit, ASTNode } from "graphql";

function clearOmittedWithables(query: ASTNode, withables: string[] = []) {
  const shouldOmit = (variable: string, withables: string[]) => {
    return variable.startsWith("with") && !withables.includes(variable);
  };

  return visit(query, {
    VariableDefinition: {
      leave(node) {
        if (shouldOmit(node.variable.name.value, withables)) {
          return null;
        }
      },
    },
    Field: {
      leave(node) {
        for (const directive of node?.directives || []) {
          if (directive.name.value === "include") {
            for (const argument of directive?.arguments || []) {
              if (shouldOmit(argument.value.name.value, withables)) {
                return null;
              }
            }
          }
        }
      },
    },
  });
}
devdev
  • 11
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 07 '22 at 06:55