Handling errors in GraphQL
Tags: graphql, prisma, errors
Published: 2018-02-14 09:26:09

---
title: Handling errors in GraphQL
published: true
description: My approach of handling errors in GraphQL
tags: GraphQL, Prisma, Error handling
---

There has been some [discussions](https://github.com/graphcool/prisma/issues/1738) recently about how to handle errors in GraphQL resolvers. I mentioned [apollo-errors](https://github.com/thebigredgeek/apollo-errors) because I had very good experiences with it. In this article, I want to take the chance and describe my approach of handling errors in a GraphQL API.  

## Anatomy of an error

Before diving deep into how to establish a proper error handling, I would like to differentiate a little bit what kind of errors we are talking about here. Basically, as in all user-facing systems, there are two possible error types:

  * `Controlled errors`: An exception which indicates that the user did something wrong (e.g. Wrong login credentials, etc.)
  * `Uncontrolled errors`: The counterpart. An exception that indicates that something really bad happened (e.g. storage system not available, etc.)

The ones we are most interested in are the `controlled errors`. These are the ones which you as the software engineer define and throw when the particular case has happened. `Uncontrolled errors`, as the name states, are the ones which can happen all the time. Even if they are not _controllable_, you will learn how to handle them gracefully as well.  

## The common approach

When reading about GraphQL, you will often see the following example:

```js
if (!areCredentialsValid) {
    throw new Error("Authentication required");
}
```

This is a simple approach and might be sufficient in most cases. The downside here is that a respective client has a hard time figuring what kind of an error this actually is. A `err.message === "Authentication required"` in the client is not cool at all.

It would be great to have a kind of error type, right? This is where [apollo-errors](https://github.com/thebigredgeek/apollo-errors) comes to play. Let's go!

## A more robust approach

Let's consider the following scenario: We have a login mutation and we want to throw an error when the user entered wrong credentials. A possible type could be `WrongCredentialsError`. The first step to do is creating the actual error type:

```ts
// path: resolvers/mutation/login/errors/WrongCredentialsError.ts

import { createError } from "apollo-errors";

const WrongCredentialsError = createError("WrongCredentialsError", {
    message: "The provided credentials are invalid."
});

export { WrongCredentialsError }
```

Now where we have our error type, we can throw it from our `login` mutation resolver:

```ts
// path: resolvers/mutation/login/index.ts

import { WrongCredentialsError } from "./errors/WrongCredentialsError";

interface LoginInput {
  username: string;
  password: string;
}

const login = await (parent, args: LoginInput, context: Context, info) {
    const user = await context.db.query.user({where: {username: args.username}});

    const areCredentialsValid = checkCredentials(user, args.password);

    if (!areCredentialsValid) {
        throw new WrongCredentialsError();
    }
};
```

So when this mutation gets executed and the user entered wrong credentials the GraphQL API would respond with:

```json
{
  "data": {},
  "errors": [
    {
      "message":"The provided credentials are invalid.",
      "name":"WrongCredentialsError",
      "time_thrown":"2018-02-14T00:40:50.954Z",
    }
  ]
}
```

Pretty, isn't it? So, in theory the GraphQL API would respond with this. There is one missing puzzle piece. Due to the different error structure, we have to tell the GraphQL API endpoint that those errors should be formatted differently.

But no worries, installing the formatter is an one-time shot and easily done. The following describes how to hook the formatter up on a [graphql-yoga](https://github.com/graphcool/graphql-yoga) based application.

```js
import { GraphQLServer, Options } from "graphql-yoga";
import { formatError } from "apollo-errors";

const options: Options = {
  formatError
};

const server = new GraphQLServer({ typeDefs, resolvers })
server.start(options, () => console.log('GraphQL API is running on localhost:4000'))
```

That's it! You're able to throw named `controlled errors` now.

## Handling uncontrolled errors gracefully

As promised above, I mentioned to give you an approach to handle `uncontrolled errors` gracefully as well. You may have read from the code snippets, that I use [Prisma](https://www.prismagraphql.com/) for interacting with my database. Let us assume that I've messed something up (e.g. sent a stuffy query to my database, etc.). In those cases, where something really bad happened, we want to inform the client that a `FatalError` occurred. How can we achieve this?

One approach would be to put each Prisma interaction in a `try / catch` and throw the `FatalError` there. That would work, but is pretty cumbersome because you have to handle that in all your resolvers.

The other approach could be to wrap all our resolvers into a wrapper that executes the actual resolver and checks if that resolver didn't throw an `uncontrolled error`. Let us call this wrapper `helmet`. It could look like:

```js
// path: resolvers/helmet.ts

import { FatalError } from "./errors/FatalError";

const helmet = (resolver) => async (...args) => {
  try {
    //
    // Try to execute the actual resolver and return
    // the result immediately.
    //
    return await resolver(...args);
  } catch (err) {
    //
    // Due to the fact that we are using Prisma, we can assume
    // that each error from this layer has a `path` attribute.
    //
    // Note: The `FatalError` has been created before by
    // using `apollo-errors` `createError` function.
    //
    if (err.path) {
      throw new FatalError({ data: { reason: err.message } });
    } else {
      throw err;
    }
  }
};

export { helmet };
```

In order to actually handle the `uncontrolled errors` gracefully, you have to wrap your resolvers into that `helmet` function. Here for example, we use the `login` mutation described above:

```js
// path: resolvers/mutation/index.ts

import { helmet } from "../helmet";

import { login } from "./login";

const Mutation = {
  login: helmet(login)
  // ...
};

export { Mutation };
```

## Conclusion

Even when just throwing an `Error` object right away might be sane in some scenarios, I would suggest considering an approach like the one described in this post for larger applications. Remember, one of GraphQL's strengths is its expressiveness. Why shouldn't you treat your errors also like that?

I hope you enjoyed the post and I'm happy to hear your thoughts :)