Handling GraphQL Errors with Hasura & React
Tags: graphql, webdev, react, errors
Published: 2019-12-03 11:50:35

---
title: Handling GraphQL Errors with Hasura & React
published: true
date: 2019-11-26 09:52:33 UTC
tags: graphql, webdev, react, error handling
canonical_url: https://blog.hasura.io/handling-graphql-hasura-errors-with-react/
---

![](https://blog.hasura.io/content/images/2019/11/Handling-errors--blog.png)

_This tutorial was written and published as part of the [Hasura Technical Writer Program](https://blog.hasura.io/the-hasura-technical-writer-program/)_

# Table of Contents

- [Introduction](#1)
- [Errors: REST Vs GraphQL](#2)
- [An introduction to GraphQL Errors](#3)
  - [Special case GraphQL errors with Hasura](#4)
- [Custom error handling with React](5)
  - [404 resource not found error](#6)
  - [Network Errors / Server Errors](#7)
- [GraphQL Errors](#8)
  - [Hasura GraphQL API](#9)
  - [Handling errors at top level](#10)
  - [Custom logic on certain errors](#11)
  - [Handling Errors at component level](#12)
- [Error policies (apollo client)](#13)
- [Summary](#14)

# Introduction <a name="1"></a>

Unlike REST APIs, GraphQL API responses do not contain numerical codes _by default_. The GraphQL spec leaves it up to GraphQL tools to show / not-show GraphQL errors.

This makes it important for people working with GraphQL to understand the errors and how these errors are handled by their GraphQL tool of choice.

In this article, I will cover:

- A quick introduction to common errors experienced in GraphQL APIs
- How to handle GraphQL errors while building APIs with Hasura
- Building custom error pages on a client side React app

# Errors: REST Vs GraphQL <a name="2"></a>

**REST** API’s use various API response codes which are returned with every API  request to tell the users/developers what happened to their request.  This is kind of obvious to someone working with **REST** , but **GraphQL** doesn’t work that way.

![](https://blog.hasura.io/content/images/2019/10/custom_errors1.png)

GraphQL responses do not contain numerical codes _by default_, and in case of an error, return an `errors` array with description of what went wrong. See the sample errors array below:

```
"errors": [{
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["hero", "heroFriends", 1, "name"]
  }]
```

The [**GraphQL spec**](https://graphql.github.io/graphql-spec/) generally [discourages adding properties to error objects](https://graphql.github.io/graphql-spec/June2018/#sec-Errors), but does allow for it by nesting those entries in an `extensions` object.

> GraphQL services may provide an additional entry to errors with key `extensions`. This entry, if set, must have a map as its value. This entry is  reserved for implementers to add additional information to errors however they see fit, and there are no additional restrictions on its  contents. ([docs](https://graphql.github.io/graphql-spec/June2018/#sec-Errors)).

This `extensions` object is used by GraphQL servers (including Hasura) to add  additional properties to the errors object. For example, sample `errors` array returned by Hasura looks like this:

```
“errors”: [{
 “extensions”: {
   “path”: “$.selectionSet.post.selectionSet.name”,
   “code”: “validation-failed”
 },
   “message”: “field \”name\” not found in type: ‘post’”
 }]
```

Hasura returns a `extensions.code`  object which can be used to classify errors and show appropriate response on the client side. In this post, I will use this object to show custom error-pages on a React client.

But first let’s learn  about the common GraphQL errors and how they are handled in Hasura.

# An introduction to GraphQL Errors <a name="3"></a>

GraphQL Errors fall into the following categories :

- **Server errors:** These  include errors like 5xx HTTP codes and 1xxx WebSocket codes. Whenever  server error occurs, server is generally aware that it is on error or is  incapable of performing the request. Server errors may also occur due  to closing of websocket connection between client and server, which may  happen due to various reasons (see [CloseEvent](https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent) for different types of 1xxx error codes). No data is returned in this case as GraphQL endpoint is not reached.
- **Client errors:**  These include errors like malformed headers sent by client,  unauthorized client, request timeout, rate-limited api, request resource  deleted, etc. All the client errors return 4xx HTTP codes. Same with  server errors, no data is returned.
- **Error in parse/validation phase of query** :  These include errors while parsing the GraphQL query. For example, if  client sends malformed GraphQL request, i.e. syntax error. Or if the  query does not pass GraphQL internal validation, i.e. client sent inputs  that failed GraphQL type checking. In both these cases, no partial data  can be returned. In case of [validation error](https://graphql.org/learn/validation/), `errors`  array is returned showing what went wrong, while queries with syntax  errors are usually not sent to GraphQL endpoint and are caught at the  client side.
- **Errors thrown within the resolvers** :  Resolver errors may occur due to lots of reasons, depending on the  implementation of resolver functions. For example, errors like poorly  written database queries, or errors thrown on purpose like restricting  users from particular countries to access some data. Most importantly,  these kind of errors can return partial data/fields that are resolved  successfully alongside an error message.

Some of these errors do not apply for **Hasura GraphQL Engine**.  For example, resolver errors (unless you are writing custom resolvers,  in which case you have to take care of the code being error-free).

### Special case GraphQL errors with Hasura <a name="4"></a>

There are 2 cases in which Hasura itself will throw errors:

**Directly altering tables / views:** If the tables/views tracked by the GraphQL engine are directly altered using `psql` or any other PostgreSQL client, Hasura will throw errors. To troubleshooting those errors, see [hasura docs](https://docs.hasura.io/1.0/graphql/manual/troubleshooting/index.html).

**Partial Data** : Hasura enforces query completeness - a query that returns incomplete data will fail. _Partial data is returned only if the query/mutation deals with **remote schema** , depending on the resolvers written by developers._

Now let’s jump into implementation of error pages.

# Custom error handling with React <a name="5"></a>

For implementing error pages, I will use the code from a [hackernews-clone app](https://github.com/abhi40308/hackernews-clone) I made as boilerplate. You can easily follow along and add error pages in your app  accordingly. The final code is hosted [here](https://github.com/abhi40308/custom-error-pages-graphQL).

### 404 resource not found error <a name="6"></a>

Let’s first start by simply adding a `404 resource not found` error page, which is shown when user goes to any unspecified route. This can be simply achieved using routing alone. In `App.js`, we have to make the following changes:

{% gist https://gist.github.com/abhi40308/fb816c54866c6deb04bc3f0ef725cd3f.js %}

Notice  that you just have to add a wild card Route with and asterisk(‘\*’) in  the end, which matches if any other routes does not match.

Now we can create the `NotFound` component as :

{% gist https://gist.github.com/abhi40308/1ede11f25585aa670b29817cedfc73fb.js %}

We get a 404 error whenever user enters an unspecified route/url:

![](https://blog.hasura.io/content/images/2019/10/custom_error-2.png)<figcaption>Any unspecified route is matched with asterisk(*) and 404 page is shown</figcaption>

### Network Errors / Server Errors <a name="7"></a>

Network Errors are errors that are thrown outside of your resolvers. If `networkError` is present in your response, it means your entire query was rejected,  and therefore no data was returned. Any error during the link execution  or server response is network error.

For example, the client failed to connect to your GraphQL endpoint, or some error occurred within your request middleware.

The best way to catch network errors is to do it on top-level using  the [**apollo-link-error**](https://www.npmjs.com/package/apollo-link-error) library. `apollo-link-error` can be used to catch and handle server errors, network errors, and GraphQL errors. `apollo-link-error` can also be used to do some custom logic when a GraphQL or Network error occurs.

Now let’s implement network-error page using `apollo-link-error`. In `App.js`, we have to make the following changes:

{% gist https://gist.github.com/abhi40308/bd32dd8987d1e1d81a38bcdc2ce99a75.js %}

Note that in `line 8`, we have intentionally changed the GraphQL endpoint `uri` to replicate a network error. We defined `onError` which catches both `graphQLErrors` and `networkErrors` and allows us to do custom logic when error occurs. Every time `networkError` occurs, the `if` statement in `line 18` is executed, and we redirect the user to a network-error page using `react-router` `history` prop (see `line 20`). In most simple terms, [`history`](https://reacttraining.com/react-router/web/api/history) object stores session history, which is used by `react-router` to navigate to different paths.

We push the path `network-error` on `history` object, and we have defined the path in routes (`line 32`). Thus, when the `if` statement executes, the user is automatically redirected to `/network-error` url.

> See [this](https://stackoverflow.com/questions/53539314/what-is-withrouter-for-in-react-router-dom) thread to better understand `react-router` and `history` object. Note that we are using `withRouter` in `App.js` to get access to the `history` object through `props`.

We will now create `NetworkError` component as:

{% gist https://gist.github.com/abhi40308/00dd2f3df74c15a7abb9d0cdfc8a527c.js %}

We get a network error, whenever the client cannot connect to the server:

![](https://blog.hasura.io/content/images/2019/10/custom_erro-3.png)<figcaption>Whenever a network error occurs, user is redirected to /network-error</figcaption>

# GraphQL Errors <a name="8"></a>

Hasura provides [various API’s](https://docs.hasura.io/1.0/graphql/manual/api-reference/index.html), but our react client will make requests to the GraphQL API.

### Hasura GraphQL API <a name="9"></a>

All GraphQL requests for queries, subscriptions and mutations are made to the [**Hasura GraphQL API**](https://docs.hasura.io/1.0/graphql/manual/api-reference/graphql-api/index.html) **.** All requests are `POST` requests to the `/v1/graphql` endpoint.

The `/v1/graphql` endpoint returns HTTP 200 status codes for all responses.

Any error that is thrown by the Hasura GraphQL API, will fall under **GraphQL Errors.** Hasura GraphQL API throws errors, returning an `errors` array having `errors[i].extensions.code` field with pre-defined codes. These codes can be used to classify errors and do custom logic accordingly.

Note: Hasura GraphQL API `errors-codes` are not documented currently, see this [open issue](https://github.com/hasura/graphql-engine/issues/2920) for more information.

[Apollo-link-error](https://www.npmjs.com/package/apollo-link-error) and [apollo/react-hooks](https://www.apollographql.com/docs/react/api/react-hooks/) make GraphQL error handling easy for us. By default, we want our app to  display global error pages (for example, a page with message “oops  something went wrong”) whenever we encounter some `query-validation` errors or `data-exception` errors. But we also want the flexibility to be able to handle an error in a specific component if we wanted to.

For  example, if a user was trying to upvote an already upvoted post, we  want to display an error message in-context with some notification bar,  rather than flash over to an error page.

### Handling errors at top level <a name="10"></a>

Top level errors can be handled using **apollo-link-error** library. For example, if we are trying to query a field which is not present, a `validation-failed` error would be returned by Hasura GraphQL API. Or trying to mutate a field with string value but the field accepts an integer, `data-exception` error will be thrown.

Example error responses returned by Hasura GraphQL API:

```
{
 “errors”: [{
    “extensions”: {
    “path”: “$.selectionSet.dogs.selectionSet.name”,
    “code”: “validation-failed”
   },
   “message”: “field \”name\” not found in type: ‘dogs’”
 }]
}{
  "errors": [{
      "extensions": {
        "path": "$.selectionSet.insert_dogs.args.objects",
        "code": "data-exception"
      },
      "message": "invalid input syntax for integer: \"a\""
    }]
}
```

These  are errors for which developer is at fault, and the end-users will  probably not understand what went wrong, if shown the above error  messages. In other words, these error messages are meant to help  developers. In such cases, it’s a good idea to use top-level error pages  which shows a “something went wrong” message. We will implement the  same using apollo-link-error.

In [`App.js`](https://github.com/abhi40308/custom-error-pages-graphQL/blob/master/src/components/App.js), we have to make the following changes:

{% gist https://gist.github.com/abhi40308/678d62d965c17b0715da3b339f2c1aa9.js %}

Every time a `graphQLError` occurs, `if` block in `line 7` gets executed, which triggers the `switch` case with `extensions.code` as the `switch` expression, thus we can map error-codes to logic we want to perform. Note that I haven’t put a `break` statement after `data-exception` (`line 10`) as I want to show same error-page on both `data-exception` and `validation-failed` errors. We redirect end-user to `/something-went-wrong` route in case of these errors.

We will now create `SomethingWentWrong` component as:

{% gist https://gist.github.com/abhi40308/3a54703bb119364c6ceabb1ca332113f.js %}

On validation-failed error, we get a “something went wrong” page:

![](https://blog.hasura.io/content/images/2019/10/custom-error-5.png)

### Custom logic on certain errors <a name="11"></a>

We can also do some custom logic in case of certain error rather than redirecting to error-pages.

For example, if the error occurs while validating `JWT` (jwt’s are used for authentication), or if the `JWT` has expired, we can write custom logic to refetch the `JWT`, and send back the api request. Errors array:

```
{
  "errors": [{
        "extensions": {
        "path": "$",
        "code": "invalid-jwt"
      },
      "message": "Could not verify JWT: JWSError (JSONDecodeError \"protected header contains invalid JSON\")"
  }]
}{
  "errors": [{
        "extensions": {
        "path": "$",
        "code": "invalid-jwt"
      },
      "message": "Could not verify JWT: JWTExpired"
  }]
}
```

We will now write custom logic to handle these errors. In [`App.js`](https://github.com/abhi40308/custom-error-pages-graphQL/blob/master/src/components/App.js), we will make the following changes:

{% gist https://gist.github.com/abhi40308/fc5d9967a1053e75cf83970e265074f8.js %}

If the error-code is `invalid-jwt`, we refetch the `JWT` and try the API request again with new authorization header.

Here is a diagram of how the request flow looks like now:

![](https://blog.hasura.io/content/images/2019/10/request-flow.png)

### Handling Errors at component level <a name="12"></a>

Errors can also be handled at component level, using functions provided by [`apollo-react-hooks`](https://www.apollographql.com/docs/react/api/react-hooks).  There may be many reasons why we would want to handle errors at  component level, for example, you may want to do some component-level  logic, or display notifications if some particular error happens.

Here,  we will be handling unique key constraint violation error, which is  preventing a user to upvote an already upvoted post. Error array  returned by Hasura GraphQL API:

```
{
  “errors”:[{
      “extensions”: {
      “path”:”$.selectionSet.insert_point.args.objects”,
      ”code”:”constraint-violation”
    },
    ”message”:”Uniqueness violation. duplicate key value violates unique constraint \”point_user_id_post_id_key\””
  }]
}
```

We have a `post` component which is using `apollo/react-hooks` function `useMutation` to mutate data on the server. When the above error is thrown, we catch the error and check for error-code.

{% gist https://gist.github.com/abhi40308/1f8768d4e2cb893a6bdfd9a47222b897.js %}

We can access `errors` array returned by Hasura using `error.graphQLErrors`. Note that the `errors` array may contain more than one error, so we are iterating over the array to check if the error code `constraint-violation` is present. If a match is found, we show a toast notification with error message.

I am using [react-toastify](https://github.com/fkhadra/react-toastify) to show error notifications. Now, whenever user tries to upvote a post already upvoted by him/her, error notification pops up:

![](https://blog.hasura.io/content/images/2019/10/error-gif.gif)<figcaption>Whenever user tries to upvote already upvoted post, error notification is shown</figcaption>

# Error policies (apollo client) <a name="13"></a>

At  last, if you are writing custom resolvers and using remote schemas with  Hasura, your queries/mutation may return partial data with errors  depending on implementation of the resolvers. In that case, apollo `errorPolicy` may come handy.

You can simply set `errorPolicy` on each request like so:

```
const { loading, error, data } = useQuery(MY_QUERY, { errorPolicy: 'all' });
```

Now, if server returns partial data and error, both data and error can be recorded and shown to user. Check out [this](https://www.apollographql.com/docs/react/data/error-handling/#error-policies) link to know more about `errorPolicy`.

# Summary <a name="14"></a>

You now know how to handle errors while building GraphQL APIs using the Hasura GraphQL Engine. If you have any comments, suggestions or questions - feel free to let me know below.

## References:

- [The Definitive Guide to Handling GraphQL Errors](https://itnext.io/the-definitive-guide-to-handling-graphql-errors-e0c58b52b5e1)
- [Full Stack Error Handling with GraphQL and Apollo](https://blog.apollographql.com/full-stack-error-handling-with-graphql-apollo-5c12da407210)
- [Error handling](https://www.apollographql.com/docs/react/data/error-handling/)
- Error images: [https://dribbble.com/mayankdhawan/projects/567197-UrbanClap-Empty-States](https://dribbble.com/mayankdhawan/projects/567197-UrbanClap-Empty-States)

## About the author 

[Abhijeet Singh](https://github.com/abhi40308) is a developer who works across a range of topics including fullstack Development, Android, Deep  Learning, Machine Learning and NLP. He actively takes part in  competitive programming contests and has interest  in solving  algorithmic problems. He is a startup enthusiast and plays  table tennis  and guitar in spare time.