Error Handling in GraphQL
Tags: graphql, typescript
Published: 2020-11-16 12:55:58

---
title: Error Handling in GraphQL
published: true
description: GraphQL servers are able to handle errors by default, both for syntax and validations errors. But often this is not sufficient for more complex situations or to sophistically handle the errors from a frontend application.
tags: GraphQL, TypeScript
cover_image: https://d2uusema5elisf.cloudfront.net/n/20201009220616277_062.jpg
canonical_url: https://www.newline.co/@royderks/error-handling-in-graphql--1746e2d6
---

GraphQL servers are able to handle errors by default, both for syntax and validations errors. You've probably already seen this when using *GraphiQL* or any other playground to explore GraphQL APIs. 

> More detailed information on error handling is also available in my new book [Fullstack GraphQL](https://newline.co/fullstack-graphql). {% twitter 1317026521274634240 %}

But often the default way is not sufficient for more complex situations or to sophistically handle the errors from a frontend application. So let's dive into how to improve this.

## GraphQL Error Object

Error handling is described in the GraphQL specification and is part of the default structure of any GraphQL response. This response consists of 3 fields:

* The `data` field, containing the result of the operation

* The `errors` field, containing all the errors that occurred during the execution of the operation

* An optional `extensions` field that contains meta data about the operation

The simplest type of error that you can get is when you in example try to use an operation that's not present in the schema of your GraphQL API. Suppose we have an API that serves as the backend for a music application. Using queries and mutations, you will be able to view tracks, add playlists, and save tracks to playlists that you've created.

One of the operations for that API is a mutation to add a track to a playlists, which is called `saveTrackToPlaylist`. 

```graphql
saveTrackToPlaylist(input: { playlistId: 1, trackId: 1 }) {
  id
  title
}
```

But suppose we make a mistake when spelling the mutation in the GraphQL playground. What would happen? The server will throw a default GraphQL error, as the misspelled mutation is not present in the schema:

![GraphQL Default Error Handling](https://s3.amazonaws.com/assets.fullstack.io/n/20201112134926285_Screenshot%202020-11-12%20at%2014.36.13.png)

The response object has the previously mentioned `error` field and a message stating the error: `Cannot query field \"saveTrrackToPlaylist\" on type \"Mutation\". Did you mean \"saveTrackToPlaylist\"?`. As you can see GraphQL graciously prevents you in sending non-existing operations to the server. Similar errors are thrown when your operation variables or requested fields are incorrect.

When you have an error that's not related to the GraphQL schema, you would have to throw an error from the resolvers of your GraphQL server. This can simpy be done by throwing an error from the resolver. This would looks something like this for the music application server:

```typescript
async function saveTrackToPlaylist(
  _: any,
  { input }: any,
  { knex }: Context,
): Promise<any> {
  if (!knex) throw new Error('Not connected to the database');

  const { playlistId, trackId } = input;

  const playlist = await knex('playlists').where('id', playlistId).select();
  const track = await knex('tracks').where('id', trackId).select();

  if (!playlist.length) throw new Error('Playlist not found');
  if (!track.length) throw new Error('Track not found');

// ...

}
```

In the resolver an error is thrown when the playlist or track that you define for the `saveTrackToPlaylist` mutation are not present in the database. The error message will again be added to the `errors` field of the GraphQL response object.

![GraphQL Stacktrace](https://s3.amazonaws.com/assets.fullstack.io/n/20201112140114840_graphql-playground-error-stacktrace.png)

The snippet above has been truncated but the actual response in the GraphQL playground is a huge chunk of JSON, which makes it hard to get the important information from that response.

Fortunately, the GraphQL specification allows you to add a field called `extensions` to the `error` object. To extend the `error` object, you can either throw a custom `Error` object or use predefined error methods available in Apollo Server. Apollo Server provides several predefined errors, such as `AuthenticationError`, `ForbiddenError`, and `UserInputError`, as well as the general `ApolloError`. These errors make it easier for you to debug and read errors from the GraphQL server.

## Data as error

Handling errors this way works especially well when you're using Apollo to create your GraphQL server, but there are more declarative ways of returning errors to the client. One way of doing so is by adding errors as data. This approach has several advantages:

* You no longer have to return `null` for the payload of the operations in the GraphQL resolver

* Errors become available in the GraphQL schema, and you can include them in the response.

To add errors to your data, you need to use the `Union` type (a.k.a. `Result`) in your GraphQL schema. Also, the logic in the resolver is rewritten so that next to the result or error for the operation you also need to return a type for it. 

This allows you to send the previous mutation in the following way, which has different payload types based on the return of the resolver. The mutation `saveTrackToPlaylist` now has three different payloads depending on the result of the resolver. 

```graphql
saveTrackToPlaylist(input: { playlistId: 1, trackId: 1 }) {
  ... on SaveTrackSuccess {
    playlistId
    playlistTitle
    trackId
    trackTitle
  }
  ... on SaveTrackPlaylistError {
    playlistId
    message
  }
  ... on SaveTrackError {
    trackId
    message
  }
}
```

The payload `SaveTrackSuccess` returns the playlist and tracks details when the operation is successful, while the `SaveTrackPlaylistError` and `SaveTrackError` are retuned when an error occurs. 

More implementations for error handling in GraphQL and the full source code are available it the book [Fullstack GraphQL](https://newline.co/fullstack-graphql).