2 ways of handling GraphQL errors in Apollo Client

If you use Graphql Apollo Client with React there are two ways of handling errors: query/mutation level and application level. Read what those approaches offer.

If you use Graphql Apollo Client with React, there are two ways (more precisely speaking) – two levels of handling errors:

  • operation level
  • application level

Operation-level errors handling

In this case, you have access to the dataloading, and error fields, and you can use an error object, which can be used to show a conditional error message.

const { loading, error, data } = useQuery(YOUR_QUERY);

if (error) return <p>Error :(</p>;

Of course, you can create a component responsible for displaying errors in your app.

import React from 'react';
import PropTypes from 'prop-types';

import classes from './ErrorMessage.module.css';


const ErrorMessage = (props) => {
    const { error, ...rest } = props;

    const shouldDisplayError = error && error.message ?
        <div className={classes.errorMessage} {...rest}>{error.message}</div>
        :
        null
    ;

    return shouldDisplayError;
};

ErrorMessage.propTypes = {
    error: PropTypes.shape({
        message: PropTypes.string.isRequired
    })
};

export default ErrorMessage; 

This component is really straightforward. It receives an error as a prop and displays that error to the user.

Application-level error handling

Another approach is handling errors in Application-level. It allows you to create more complex logic.

Application-error handling lets you do whatever you want with errors. For example, you can log those errors to the console in development mode or use external tracking error tools like Sentry on production.

You can use this mechanism to display messages to the user as well. Let’s imagine that you have Messages Context in your app or you have a custom hook, and there you keep the whole logic for adding/removing/displaying messages.

If you use application-level error handling, you can pass error messages to your messages/notification manager and do whatever you want with them.

There are two types of errors.

  1. GraphQL errors (like in a previous example)
  2. Network error (for example, if the app lost internet connection)

GraphQL errors

There are three types of GraphQL errors:

  • syntax error – for example, when you made a mistake in a query or mutation
  • resolver error – for example, when the GraphQL server was not able to resolve a query field
  • validation error – for example, when provided data didn’t pass validation on the server side.

Note that when there is a resolver error, the GraphQL server returns partial data, but if there is a syntax or validation error, the server doesn’t return data at all.

In the first case, the server responds with a 200 status code, otherwise returns a 4xx status code (for syntax and validation errors)

Network errors

Network errors occur when there are communication problems with the GraphQL server. In this case, the server usually responds with a 4xx or 5xx response status code and no data.

Error policies

By default, the Apollo server returns partial data when there is a resolver error, but you can change this behavior by changing the error policy. There are three error policies:

  • none – the default one – if there are errors the graphQLErrorsthe field is populated and the data field is set to undefined (even if the server returns some data in response)
  • all – both fields data and graphQLErrors are populated
  • ignore – graphQLErrorsfield is ignored and not populated

How to specify error policy

You can specify error policy globally on or query/mutation level.

Global error policy

You can set an error policy for queries and mutations using the defaultOptions object in the ApolloClient constructor. The example below shows an error policy all set for queries and an ignore policy for mutations.

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  cache: new InMemoryCache(),
  uri: 'http://localhost:3000/',
  defaultOptions: {
    query: {
      errorPolicy: 'all',
    },
    mutate: {
      errorPolicy: 'ignore',
    },
  },
});

Operation error policy

To specify error policy on the operation level, you have to pass the errorPolicy field in options object like this:

const { loading, error, data } = useQuery(YOUR_QUERY, { errorPolicy: "ignore" });

Implement application-level error handling

To implement application-level error handling, we need to use a functionality called ApolloLink.

The Apollo Link library helps you customize the data flow between Apollo Client and your GraphQL server. You can define your client’s network behavior as a chain of link objects that execute in a sequence.

Each link should represent either a self-contained modification to a GraphQL operation or a side effect (such as logging).

Take a look at a sample implementation of application-level error handling.

First, import the onError function.

import { onError } from "@apollo/client/link/error";

Second, create the errorLink:

const errorLink = onError(({ graphQLErrors, networkError }) => {
    if (graphQLErrors) {
        console.log(graphQLErrors);
    }

    if (networkError) {
        // handle network error
        console.log(networkError);
    }
});

Third, use HttpLink, and from helper method to combine a single link that can be used in the Apollo client.

import { ApolloClient, InMemoryCache, ApolloProvider, from, HttpLink } from '@apollo/client';

...

const httpLink = new HttpLink({ uri: 'https://<API_URL>' })

const appLink = from([
    errorLink, httpLink
])

const client = new ApolloClient({
    link: appLink,
    cache: new InMemoryCache(),

});

Summary

There are two types of errors that you can handle:

  1. network errors
  2. GraphQL error

There are three error policies (all, ignore, and none), and you can specify an error policy globally or on the operation level.

Moreover, there are two levels where you can handle those errors:

  1. application level
  2. component (query/mutation) level

Thanks to application-level error handling, you can use JavaScript error tracking tools on production and log errors to the console in local environments. Besides, you can use this mechanism to handle and display errors in your application.

Share the Post:

You might also like

A career in technology: How to develop your skills

Are you a programmer and would like to grow? The Internet is full of materials on how to do this. Despite this, don’t run away – I have something that will interest you. Did you know that Adam Malysz, the legendary Polish ski jumper, was a roofer before he became a flying champion? I dare not compare myself with Mr. Adam, while there are two things we have in common.

I was also a roofer and also managed to re-brand myself. Maybe not in such a spectacular way, but still. In this article, I’ll share my personal experience on my journey from roofer to programmer to tech lead and give you tips you can apply to grow and advance and maybe even dramatically change your career.

Read More
AHA! Let's bring back the simplicity of the Frontend

AHA! Let’s bring back the simplicity of Frontend

Have you wondered why, in this day and age, when we have access to the latest technologies and solutions, IT projects still fail? Don’t you think that we complicate our lives and work in many cases instead of simplifying it? Sometimes less is more, especially in the world of frontend! Read on to learn what an AHA stack is and how to do frontend more simply.

Read More