The Ultimate A-Z GraphQL Error Handling Best Practices Guide

Handling and Reporting GraphQL Errors with Apollo Client errorPolicy

The GraphQL response brings a new set of possible errors to every implementation.

In addition to the usual raft of errors i.e server errors, transaction errors, UI errors, you now also have to handle (whenever possible) or report GraphQL and Apollo Client errors to the user.

GraphQL is aptly suited for handling errors because it has the ability to send both data and errors in response, and it sits right between the frontend and a constellation of web services and data sources.

Apollo Server on the other hand now tacks in some common GraphQL error handling best practices right in it's core—to save you the trouble of rolling this on your own.

The Error Response in The GraphQL Spec

A GraphQL response (with errors) for a Query such as...

        
{
  hero(episode: $episode) {
    name
    heroFriends: friends {
      id
      name
    }
  }
}
        
      

...typically looks like this:

        
{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "hero", "heroFriends", 1, "name" ]
    }
  ],
  "data": {
    "hero": {
      "name": "R2-D2",
      "heroFriends": [
        {
          "id": "1000",
          "name": "Luke Skywalker"
        },
        {
          "id": "1002",
          "name": null
        },
        {
          "id": "1003",
          "name": "Leia Organa"
        }
      ]
    }
  }
}
        
      

This is, at best, an arbitrary combination of errors.

Looking at the above response, GraphQL formats error responses at follows:

  1. When errors are encountered, the errors entry is present and non-empty.
  2. If the data entry is present with a null value, the errors entry will carry the error details.
  3. Additionally, is the data entry is not present, the errors entry must be non-empty.

It is clear from the above example that GraphQL returns errors and data in the same response—which is nice! But, this is insufficient for production apps for several reasons:

  1. The error response is not rich enough: The error description message alone will typically not suffice for an end user to fix their problem unaided.
  2. It is hard for the developer to programatically monitor the health of a GraphQL service with these error responses alone.
  3. Developers need a way to handle errors automatically.

The GraphQL spec provides a little guidance on how to handle errors by suggesting additional entries with key extensions to the errors entry as follows.

        
{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "hero", "heroFriends", 1, "name" ],
      "extensions": {
        "code": "CAN_NOT_FETCH_BY_ID",
        "timestamp": "Fri Feb 9 14:33:09 UTC 2018"
      }
    }
  ]
}
        
      

The Spec is however quick to caution against providing additional entries besides errors and data so as to future-proof GraphQL services.

Let's see how we can use Apollo to handle errors in a GraphQL service.

In the Spec implementation responses we end up with an arbitraty combination of server errors, network errors, GraphQL errors to tell client what went wrong—which leads us straight to complex custom error handling logic.

Let's see how we can easily handle errors with Apollo Server

Handling GraphQL Errors with Apollo Server

Apollo Client distinguishes between two kinds of errors according to where the error occurred; GraphQL errors and Network errors.

A networkError is thrown outside of resolvers; meaning that the entire query was rejected and no data was returned. In contrast, graphqlErrors are thrown within resolvers.

GraphQL Error Handling Best Practices in Apollo Server

Best Practices Chart