Hi,
In my application, as is quite common, I handle errors coming back from the server in the same global way, throughout the app. Right now, every time I make a mutation to the server, I need to include error handling code every time, which is just boilerplate overhead.
In my specific case, I use react with redux, and dispatch an action on error to display a snackbar.
So, every mutation has this same added code:
mutate(...).catch(err => {
const error = err.graphQLErrors[0].message
props.showUserFeedback(error)
})
where I need to connect the component to redux just for that action, and so forth.
I propose some kind of global error handling in the apollo client settings, maybe with a different way to handle each kind of error, and that could be overridden.
Thanks!
you can create a custom network interface to handle this:
http://dev.apollodata.com/core/network.html#custom-network-interface
you can wrap the what apollo client network interface you are using then add in your error handling in there.
Awesome thanks.
I actually looked into it, but missed GraphQLResult
Closing
@jazzdragon you're not the only one to have missed that. The documentation could really use a "global error handling" section or something; currently the only way a user can find out how to handle errors globally in Apollo is to:
Far more likely they'll discover the local error handling and think that's all Apollo offers, because that's all that's highlighted in the documentation.
I agree with @machineghost. Even some example code would help.
@fc any simple example on wrapping the error as you mention would be great!!
I did something along these lines:
const networkInterface = createNetworkInterface({uri})
const handleErrors = ({ response }, next) => {
// clone response so we can turn it into json independently
const res = response.clone()
// if it's not user error, we skip this afterware (for example a 401)
if (!res.ok) {
// handle network errors based on res.status here, for example:
if (res.status === 500) {
showUserFeedback('internal server error')
}
return next()
}
// handle apollo errors
res.json().then(json => {
each(json.data, data => {
if (data && data.errors && data.errors.length) {
showUserFeedback(data.errors[0])
}
})
next()
})
}
networkInterface.useAfter([{
applyAfterware: handleErrors,
}])
const client = new ApolloClient({
networkInterface,
})
Obviously showUserFeedback is implemented somewhere...
Hope this helps!
@jazzdragon can you please share the whole implementation? I don't understand what you mean with "showUserFeedback is implemented somewhere"
@lobosan it's up to you, how you want to handle the errors in your application. For example:
const showUserFeedback = (error) => console.error(error)
@jazzdragon The only I have seen so far with your solution is around request that ends pretty bad. Like with a failed to fetch or with a CORS issue. Apollo isn't calling the useAfter
callbacks.
Same here, when the network disconnects, in the console I get
Unhandled (in react-apollo) Error: Network error: Failed to fetch
and
DOMException: Failed to execute 'postMessage' on 'Window': TypeError: Failed to fetch could not be cloned.
at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:20:14)
Checking to see if the second error goes away if I temporarily remove Apollo Chrome Dev Tool.
@oliviertassinari Would those errors be caught by a mutate(...).catch()?
Those were the ones I was targeting here.
@jazzdragon I think so, as well as with a query(...).catch().
@oliviertassinari Can you give a code example of how to catch or handle the Unhandled (in react-apollo) Error: Network error: Failed to fetch
error?
const showUserFeedback = (error) => console.error(error)
@jazzdragon Thanks for your solution but what if i would like to fire a Materialized Toast
alert instead of printing in the console.error
. How could i use dispatch
?
I've found this solution on the web for global handling, but looks very different from solution here:
https://dev.to/andre/react-apollo-an-approach-to-handle-errors-globally-jg
in my case I have:
const SignInWithData = graphql(signInMutation)(withRouter(SignInFormContainer));
const mapDispatchToProps = dispatch => ({
signInDispatcher(token) {
dispatch(signIn(token));
},
});
const SignInWithDataAndState = connect(
null,
mapDispatchToProps,
)(SignInWithData);
export default SignInWithDataAndState;
@jazzdragon your solution is better to handle errors codes ?
I've seen too this package:
https://github.com/thebigredgeek/apollo-errors
but i don't think can manage errors when there is no connection...
@webmobiles apollo-errors ist a package for apollo-server. I think with apollo-client you could even create a link that could emit an event with the error to a component.
yes I know , with that all errors can be transformed in just errors response like data, and don't have throws erros in client, but the problems keeps to get the error when the server is down.
@jazzdragon i have error : 'each' is not defined no-undef , from where 'each' comes ?
@jazzdragon your answer here: https://github.com/apollographql/apollo-client/issues/1692#issuecomment-324702528 is amazing!
Can you explain this to me better, please?
// clone response so we can turn it into json independently
const res = response.clone()
@jazzdragon I need to destroy res
cloned after use? How?
I just released a library that solves this problem for Apollo 2: react-apollo-network-status
Maybe this is helpful to you 🙂
@amannn do you have a declaration file for react-apollo-network-status?
@GobbaFish Hmm, what do you mean by a declaration file?
@amannn, sorry I mean a typings (.d.ts) file to enable its use with typescript
@GobbaFish Oh, I see. No, currently there's no TypeScript declaration and I only have very little experience with TypeScript.
If you like to add them via a PR, I'd be happy to merge. Or is that even the right workflow? I've seen there's also DefinitelyTyped – would you rather add the declaration to that repo or in the repo itself?
client 2+ should use apollo-link
instead https://www.apollographql.com/docs/link/links/http/#upgrade-apollo-client-10
Most helpful comment
I did something along these lines:
Obviously showUserFeedback is implemented somewhere...
Hope this helps!