Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling Apollo errors on the component side

Question

How can I react to Apollo errors in my components?

I'd like for example to display a red banner if a "network offline" error was thrown; or show a modal if an error of a certain type is displayed; or render a <Redirect> (from react-routed-dom) if another kind of error is thrown.

What I tried

I read the documentation chapter about error handling but it only explains how to setup an Apollo link that acts as a middleware to requests in order to catch errors there. As far as I know it's not possible to pass data from that link down to components given that it's a terminating link.

I tried to use error boundary components but it seems like Apollo errors are not really thrown. Not even when using the await syntax.

like image 634
Shoe Avatar asked Feb 13 '18 15:02

Shoe


People also ask

How do you handle errors in Apollo GraphQL?

On GraphQL errorsThe onError link can retry a failed operation based on the type of GraphQL error that's returned. For example, when using token-based authentication, you might want to automatically handle re-authentication when the token expires. // instead of the onError link. This just logs the error.

Does Apollo client throw an error?

Throwing errorsApollo Server throws errors automatically when applicable. For example, it throws a GRAPHQL_VALIDATION_FAILED error whenever an incoming operation isn't valid against the server's schema. Your resolvers can also throw errors in situations where Apollo Server doesn't do so automatically.

How do you handle error in useMutation?

Calling the mutate function returned by the hook returns a Promise. If the request is successful, the Promise will resolve to a response object that includes the data returned by the server. If the request fails, the Promise will reject with the error.

How is error handling done in GraphQL?

The standard error handling mechanism from GraphQL with return a JSON containing: a data key which contains the data corresponding to the GraphQL operation (query, mutation, subscription) invoked and. an errors key which contains an array of errors returned by the server, with a message and location.


1 Answers

As you already pointed out, you could use the apollo-link-error package Link.

If you also use react-router-dom for routing between pages, it is possible to use the browser history or the Redirect component to redirect to an error page with a state object (routing history). The state object contains the error that you would like to show.

The setup could look like this:

  • Create browser history

import { History, createBrowserHistory } from 'history';
   
/* If using Typescript, you can make this object Readonly as follows */
export type ReadonlyBrowserHistory = Readonly<History>
const browserHistory: ReadonlyBrowserHistory = createBrowserHistory();

export default browserHistory;
  • Add Router with browser history (w/ option to make history properties readonly)

import browserHistory from './browserHistory'
import apolloClient from './apolloClient'

... 

ReactDOM.render((
   <ApolloProvider client={apolloClient}>
      <Router history={browserHistory}>
         <App />
      </Router>
   </ApolloProvider>
), document.getElementById("root"));
  • add link with routing to apollo client

import browserHistory from './browserHistory'

const errorLink = onError(({ networkError, graphQLErrors }) => {
   if (graphQLErrors) {
      browserHistory.push("/error", { errors: graphQLErrors });
   }
   else if (networkError) {
      browserHistory.push("/error", { errors: networkError });
   };
});

const httpLink = new HttpLink({
   uri: httpUri
});

const httpLinkWithErrorHandling = ApolloLink.from([
   errorLink,
   httpLink,
]);

const apolloClient = new ApolloClient({
   link,
   ...
});

export default apolloClient;
  • The error page can retrieve the errors from the route location prop

const ErrorPage = ({ location: { state } }) => {

  console.log(state);

  return (<div>error page</div>)
};
like image 190
Locco0_0 Avatar answered Oct 10 '22 06:10

Locco0_0