react-apollo: An approach to handle errors globally
Tags: react, graphql, apollo
Published: 2017-10-02 16:54:01

---
title: "react-apollo: An approach to handle errors globally"
published: true
description: 
tags: react, GraphQL, Apollo
---

Well, I had quite a journey today and I would like to share it with you. I'm – like most of you – a huge fan of [GraphQL](http://graphql.org/) and the [Apollo Stack](https://www.apollodata.com/). Those two technologies + React: declarative rendering + declarative data fetching â¤ï¸ - Is there anything that would make a dev happier? I guess there are many things, but anyways. One thing that bothered me a lot today was handling errors globally. ðŸ˜¤

Imagine the following scenario: An unexpected error occurred. Something really bad. The UI can't and shouldn't recover from that state. You would love to display a completely different UI which informs the user about that case. The Apollo client, or the `react-apollo` binding to be precisely, is pretty good when it comes to handling occurred errors on a local level. Something in the vein of: You have a component that "binds" to a GraphQL query and whenever an error occurred you will display something different within *that* component:

```js

import { compose } from "recompose";
import { graphql, gql } from "react-apollo";

import { ErrorHandler } from "./components";

const NewsList = compose(
  graphql(gql`
    query news {
      id
      name
    }
  `)
)(({ data }) =>
  <div>
    {data.loading ? (
      <span>Loading ...</span>
    ) : data.errors ? (
      <ErrorHandler errors={data.errors} />
    ) : (
      <ul>
        data.news.map(entry => <li key={entry.id}>{entry.name}</li>)
      </ul>
    )}
  </div>
);
```

There is nothing wrong with that approach, except that it doesn't fulfil our aspired scenario in which we want to display an UI the user can't "escape" from. How can we achieve that then?

## Afterwares to the rescue!

The Apollo Client comes with a mechanism called [Afterware](http://dev.apollodata.com/core/network.html#networkInterfaceAfterware). An `Afterware` gives you the possibility to hook you right into the network layer of the Apollo client. It is a function that gets executed whenever a response comes from the server and gets processed by the client. An example:

```js
// graphql/index.js

import ApolloClient, { createNetworkInterface } from "react-apollo";

const createClient = ({ endpointUri: uri }) => {
  const networkInterface = createNetworkInterface({ uri });

  networkInterface.useAfter([{
    applyAfterware({ response }, next) {
      // Do something with the response ...
      next();
    }
  }]);

  return new ApolloClient({ networkInterface });
};

export { createClient };
```

Before diving into how to handle the actual error, I would like to complete the example by defining how to create the actual client and use it in your app. The following would be your entry component that bootstraps your application:

```jsx
// index.js
import { render } from "react-dom";
import { ApolloProvider } from "react-apollo";

import { App } from "./App";
import { createClient } from "./graphql";

const $app = document.getElementById("app");

const client = createClient({
  endpointUri: "https://api.graph.cool/..."
});

render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>
, $app);
```

So that is this. Creating the client and passing it to the `ApolloProvider`. Now what? I promised you that we wan't to display a scene which doesn't allow the user to interact with the app. After some tinkering I came to the conclusion that there is a simple solution for that. So here is the dopey idea: Let's pass an additional function to the `createClient` function, called `onError` which takes an error object and performs a complete new `render` on the `$app` DOM node. That would allow us to unmount the corrupt UI and render a different component for displaying the respective error case to the user ðŸ¿

First of all: Let's adjust the bootstrapping of the app by defining the `onError` function and passing it to the `createClient` call:

```js
// index.js
import { render } from "react-dom";
import { ApolloProvider } from "react-apollo";

import { App } from "./App";
import { createClient } from "./graphql";

const $app = document.getElementById("app");

const client = createClient({
  endpointUri: "https://api.graph.cool/...",
  onError: error => render(
    <MyErrorHandler error={error} />
  , $app)
});

render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>
, $app);

```

Afterwards, we have to adjust our `Afterware` so that it calls that passed `onError` function whenever the server responds with errors:

```js
// graphql/index.js

import ApolloClient, { createNetworkInterface } from "react-apollo";

const createClient = ({ endpointUri: uri, onError }) => {
  const networkInterface = createNetworkInterface({ uri });

  networkInterface.useAfter([{
    applyAfterware({ response }, next) {
      if (response.status === 500) {
        return onError(new Error(`A fatal error occurred`));
      }

      next();
    }
  }]);

  return new ApolloClient({ networkInterface });
};

export { createClient };
```

Wohoo! That's it! From now on, your application would display your `<MyErrorHandler />` whenever an error occurred. Mission completed!

Would be great when we could use [error boundaries](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html) which has been introduced in _React 16_, but that is not possible due the not "throwing nature" of the Apollo client (which is a good thing when you want to have fine-grained error handling capabilities).


That is it from me for now. Hope you enjoyed the ride and maybe this approach is also useful for you :)

Happy coding!