How to render errors with apollo-link-error

Viewed 754

I would like to use apollo client error link to create a MUI snackbar displaying any error that is returned by graphql. The setup is a Nextjs web app using Material-ui and Apollo Client. From Apollo documentation on Error links an error link can be created which will handle errors returned by the graphql API. The Apollo error link can not render anything it self as it will return void.

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

// Log any GraphQL errors or network error that occurred
const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors)
    graphQLErrors.forEach(({ message, locations, path }) =>
      console.log(
        `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
      )
    );
  if (networkError) console.log(`[Network error]: ${networkError}`);
});

My initial thought was to use hooks and context. Creating a hook which the Apollo error link can push notifications on and a context provider in my _app.ts. However the Apollo client is not a functional component hence this will not work.

I did think about creating a function to handle onError callback in Apollo queries and mutations but it seems like a lot of work to put an onError function on each query/mutation.

1 Answers

This can be handled using context. You have to do some changes to your component hierarchy.

ContextProvider => ApolloProvider

Make sure both are used in different components. Otherwise, you will not able to access hooks.

Ex: You should be able to access the hook inside the Root component, where you can add ApolloProvider.

I've created an example hope that helps (not using apollo but you can add): https://stackblitz.com/edit/react-ts-m7swyo

import React, { createContext, useContext, useReducer } from "react";
import { render } from "react-dom";
import "./style.css";

const Context = createContext({});

const Root = () => {
  const { state, dispatch } = useContext(Context);
  return (
    <ApolloProvider
      client={
        new ApolloClient({
          link: ApolloLink.from([
            onError(({ graphQLErrors, networkError }) => {
              // Do something and dispatch to context
              // dispatch({ type: 'ERROR', error: graphQLErrors || networkError });
            }),
          ]),
        })
      }
    >
      <App />
    </ApolloProvider>
  );
};

const reducer = (state, action) => {
  if (action.type === "ERROR") {
    return { ...state, ...action.payload };
  }
  return state;
};

const App = () => {
  const [state, dispatch] = useReducer(reducer, {});
  return (
    <Context.Provider
      value={{
        state,
        dispatch,
      }}
    >
      <Root />
    </Context.Provider>
  );
};
render(<App />, document.getElementById("root"));
Related