1.0.1 • Published 5 years ago

graphql-query-utility v1.0.1

Weekly downloads
6
License
GPL-3.0
Repository
github
Last release
5 years ago

graphql-query-utility

Utility library to test and format outgoing GraphQL queries.

Installation

Unless you want to use the format method to trim out extra whitespace, this package can be saved as a dev dependency via npm:

npm install graphql-query-utility --save-dev

or yarn:

yarn add graphql-query-utility --dev

If you want to use format, you'll need to install it as a normal dependency via npm:

npm install graphql-query-utility

or yarn:

yarn add graphql-query-utility

Structure

When testing a query string, you programmatically define the structure with helper methods. The helper methods are designed to approximately represent the shape of a GraphQL query string. The helper methods generate node objects of a GraphQL tree.

query (alias: q)

query takes as many children nodes as you'd like to give it. These children can include fragmentDeclaration children. Most queries will start with a branch or branchWithArguments

branch (alias: b)

branch takes a name (string), and as many children nodes as you'd like to give it. Requires at least one child node.

branchWithArguments (alias: ba)

branchWithArguments takes a name (string), an array of argument nodes, and as many children nodes as you'd like to give it. Requires at least one child node.

leaf (alias: l)

leaf takes a name (string), and as many argument nodes as you'd like to give it (including no argument nodes at all).

argument (alias: a)

argument takes a name (string), a value (string, or null), and a boolean (true for 'quoted', false for 'unquoted'). 'Quoted' means that the value of the argument is surrounded by quotes, whereas 'unquoted' means that the value does not have quotes surrounding it.

fragmentDeclaration (alias: fd)

fragmentDeclaration takes a name (string), a type reference (string), and as many children nodes as you'd like to give it. Requires at least one child node. fragmentDeclaration nodes should only be child nodes of a query node.

fragment (alias: f)

fragment takes a name (string). Should correspond to the name of a fragmentDeclaration node.

inlineFragment (alias: if)

inlineFragment takes a name (string), and as many children as you'd like to give it. Requires at least one child node.

Example usages of structure

Verifying your query has correct structure in a unit test. This example is using jest.

import {
  argument,
  leaf,
  branchWithArguments,
  branch,
  fragment,
  inlineFragment,
  fragmentDeclaration,
  query,

  findErrors,
} from 'graphql-query-utility';

it('Outgoing query has expected structure', () => {
  /*
   In a real project you would likely have to extract the query from the code,
   possibly with mocks or argument capturing.
   This example just declares the query in the test.
  */
  const graphql = `
  {
    actors(limit: 5, sort: "ascending") {
      firstName
      lastName
      ... Thumbnail
      ... on Superstar {
        appearances {
          title
          actors(limit: 10) {
            firstName
            lastName
             ... Thumbnail
          }
        }
      }
    }
  }

  fragment Thumbnail on Person {
    imageUrl
    width
    height
  }`;

  /*
   Note the value parameter is set to `null` for each argument.
   For arguments, the value doesn't matter.  The last parameter
   (true or false) does matter.  Set it to true if the argument
   is surrounded by quotes, false if it is not.
  */
  const structure = query(
    branchWithArguments('actors',
      [
        argument('limit', null, false),
        argument('sort', null, true),
      ],
      leaf('firstName'),
      leaf('lastName'),
      fragment('Thumbnail'),
      inlineFragment('Superstar',
        branch('appearances',
          leaf('title'),
          branchWithArguments('actors',
            [
              argument('limit', null, false),
            ],
            leaf('firstName'),
            leaf('lastName'),
            fragment('Thumbnail'),
          ),
        ),
      ),
    ),
    fragmentDeclaration('Thumbnail', 'Person',
      leaf('imageUrl'),
      leaf('width'),
      leaf('height'),
    ),
  );

  expect(findErrors(graphql, structure)).toEqual([]);
});

Verifying your query has correct argument values in a unit test. This example is using jest.

import { argumentsAtPath } from 'graphql-query-utility';

it('has expected arguments and values', () => {
  /*
   In a real project you would likely have to extract the query from the code,
   possibly with mocks or argument capturing.
   This example just declares the query in the test.
  */
  const graphql = `
  {
    a
    b
    c {
      d
      e {
        f(arg1: "stuff", arg2: "more stuff", arg3: 5) {
          g
        }
      }
    }
  }`;

  /*
   argumentsAtPath uses a JSONPath-like syntax.  Each . indicates to "go in" one
   level into the query.
   */
  const actual = argumentsAtPath('c.e.f');
  expect(actual.length).toEqual(3);
  const arg1 = actual.find(arg => arg.name === 'arg1');
  const arg2 = actual.find(arg => arg.name === 'arg2');
  const arg3 = actual.find(arg => arg.name === 'arg3');

  /*
   Verify the values are as expected.  Depending on your test framework, you might
   expect that the values match a regular expression, or just have a specific value
   */
  expect(arg1.value).toEqual('stuff');
  expect(arg2.value).toEqual('more stuff');
  expect(arg3.value).toEqual('5');
});

Formatting query string

Before sending your query string to a GraphQL server, you can remove redundant whitespace with the format method. This method takes your query string as the first argument. By default, it preserves the order of your query. If you would like to sort the query alphabetically (preserves logical query structure), you can pass an optional configuration argument second. Current supported configuration options (with their default values):

{
  preserveOrder: true // Keep query order intact when true, sort alphabetically when false
}

Example usages of format

Formatting your query to remove extra whitespace

import { format } from 'graphql-query-utility';

const graphql = `
{
  removes
  the
  extra
  whitespace {
    yet (it: "preserves   all   the   whitespace")
    inside (argumentValues: "that   have   quotes") {
      hooray
    }
  }
}`;

// By default, format preserves the order of the string
const formatted = format(graphql);
console.log('Formatted', formatted);
// { removes the extra whitespace { yet(it: "preserves   all   the   whitespace") inside(argumentValues: "that   have   quotes") { hooray } } }

// But it can be overridden if you want too sort each indentationo level alphabetically.
const sorted = format(graphql, { preserveOrder: false });
console.log('Sorted', sorted);
// { extra removes the whitespace { inside(argumentValues: "that   have   quotes") { hooray } yet(it: "preserves   all   the   whitespace") } }