graphql-normalizer

1.0.0 • Public • Published

graphql-normalizer

Travis build status Coveralls NPM version Canonical Code Style

A GraphQL response normalizer designed to work with apollo-client.

How does it work?

apollo-client uses __datatype and an id values to construct a resource identifier. The resource identifier is used to normalize data. As a result, when GraphQL API response contains a resource with a repeating identifier, the apollo-client is going to read only the first instance of the resource and ignore the subsequent repetitions. We can leverage this to strip body of all duplicate resource instances.

Motivation

Consider the following schema:

interface Node {
  id: ID!
}
 
type Movie implements Node {
  id: ID!
  name: String!
}
 
type Venue implements Node {
  id: ID!
  name: String!
}
 
type Event implements Node {
  id: ID!
  venue: Venue!
  movie: Movie!
  # YYYY-MM-DD
  date: String!
  # HH:mm
  time: String!
}
 
type Query {
  events (
    date: String
  ): [Event!]!
}
 

Using this schema, you can query events for a particular date, e.g.

{
  events (date: "2017-05-19") {
    id
    date
    time
    movie {
      id
      name
    }
    venue {
      id
      name
    }
  }
}
 

The result of the above query will contain a lot of duplicate information.

{
  "data": {
    "events": [
      {
        "id": "1669971",
        "date": "2017-05-19",
        "time": "17:25",
        "movie": {
          "id": "1198359",
          "name": "King Arthur: Legend of the Sword"
        },
        "venue": {
          "id": "1000819",
          "name": "Vue Westfield London"
        }
      },
      {
        "id": "1669972",
        "date": "2017-05-19",
        "time": "20:30",
        "movie": {
          "id": "1198359",
          "name": "King Arthur: Legend of the Sword"
        },
        "venue": {
          "id": "1000819",
          "name": "Vue Westfield London"
        }
      },
      // ...
    ]
  }
}
 

I've run into this situation when building https://gotocinema.com. A query retrieving 300 events (movie screening event) produced a response of 1.5MB. When gziped, that number dropped to 100KB. However, the problem is that upon receiving the response, the browser needs to parse the entire JSON document. Parsing 1.5MB JSON string is (a) time consuming and (b) memory expensive.

The good news is that we do not need to return body of duplicate records (see How does it work?). For all duplicate records we only need to return __typename and id. This information is enough for apollo-client to identify the resource as duplicate and skip it. In case when a response includes large and often repeated fragments, this will reduce the response size 10x, 100x or more times.

Usage

You need to format the final result of the query. If you are using graphql-server, configure formatResponse.

import express from 'express';
import {
  graphqlExpress
} from 'graphql-server-express';
import {
  createResponseNormalizer
} from 'graphql-normalizer';
 
const SERVICE_PORT = 3000;
 
const app = express();
 
app.use('/graphql', graphqlExpress(() => {
  return {
    formatResponse: createResponseNormalizer()
  };
}));
 
app.listen(SERVICE_PORT);
 

Note: You must create a new instance of graphql-normalizer for each request.

Using graphql-normalizer does not require any changes to the client-side code.

Versions

Current Tags

  • Version
    Downloads (Last 7 Days)
    • Tag
  • 1.0.0
    4
    • latest

Version History

  • Version
    Downloads (Last 7 Days)
    • Published
  • 1.0.0
    4

Package Sidebar

Install

npm i graphql-normalizer

Weekly Downloads

4

Version

1.0.0

License

BSD-3-Clause

Last publish

Collaborators

  • gajus