Published at
Updated at
Reading time
3min

I watched some Graphql Summit videos and the talk 200 OK! Error Handling in GraphQL by Sasha Solomon caught my eye. She shares an approach to GraphQL error handling that made me rethink how to model GraphQL APIs.

Is every API error an actual error?

Let's have a look at one of her example queries.

{
  user(id: "someId") {
    id name
  }
}

This query requests a user field with a specific id. The question is: what should happen when the user doesn't exist? A GraphQL response includes a data and an optional errors property.

One option to treat the non-existing user is a "classical error" added to the errors object.

{
  "data": {
    "user": null
  }
  "errors": {
    {
      "path": ["user"],
      "location": [{ "line": 2, "column": 3 }],
      "extensions": {
        "message": "object not found"
      }
    }
  }
}

While this works, it feels like a mapping coming from a RESTful world to GraphQL. In this world, not found resources result in a 404 status code โ€“ a red status code.

This approach has the disadvantage that errors show up in a different location โ€“ they're in errors instead of data. That's not ideal and annoying to implement from an application side.

The question rises if you should treat a 404 (or any other expected error) like a hard error such as a very bad 500 โ€“ something went wrong after all? What if the GraphQL schema could define expected errors not as errors, but as different response types?

Expected errors are just different types of results

The significant advantage of GraphQL is that you write the query that shapes the responded data. What if you could control the errors that you want to receive, too? To make that work, Sasha shares the following approach.

When building a GraphQL API, you could stop querying for resources but start querying for results. A GraphQL API can define different resources for a single query field using union types. Let's have a look at how this works.

union UserResult = User | NotFoundUser

The schema definition above defines that the union type UserResult can result in a User or a NotFoundUser. This definition allows you to adjust your query to treat the userResult differently depending on its type.

The following query requests two users with different ids. One of the query fields results in an error.

{
  userOne: userResult(id: "someId") {
    __typeName
    ... on User {
      id
      name
    }
    ... on NotFoundUser {
      message
    }
  }
  
  userTwo: userResult(id: "someOtherId") {
    __typeName
    ... on User {
      id
      name
    }
    ... on NotFoundUser {
      message
    }
  }
}

Because the userResult response varies, you have to use conditional fragments (... on User and ... on NotFoundUser) to specify what data you're interested in depending on its type.

A possible response to this query could look like this.

{
  "data": {
    "userOne": {
      "__typeName": "User",
      "id": "someId",
      "name": "Jane Doe"
    },
    "userTwo": {
      "__typeName": "NotFoundUser",
      "message": "User is out for lunch"
    }
  }
}

By returning a User or a NotFoundUser, you can include the error response right in the query field that requests the data. The error is not included in the errors property.

The __typeName field gives you the information about what object you're dealing with to adjust your application. That's pretty neat!

Advantages of error results

I have to say this approach seems very logical to me. Her described approach to GraphQL error handling has a few advantages.

Error results keep the GraphQL query in control of the response, even in an error case. You are 100% in control of the result, whether it's a successfully queried resource or an expected error. Additionally, you can decide what error results and what details you care about and which to ignore. The query stays in control, and that's what GraphQL is about after all.

Watch the talk on YouTube

Here's the YouTube video. Highly recommended!

Oh hey, and I just learned that Sasha wrote about it on Medium, too.

If you enjoyed this article...

Join 5.2k readers and learn something new every week with Web Weekly.

Web Weekly โ€” Your friendly Web Dev newsletter
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles