Error Handling in GraphQL
GraphQL servers are able to handle errors by default, both for syntax and validations errors. You've probably already seen this when using GraphiQL or any other playground to explore GraphQL APIs. But often the default way is not sufficient for more complex situations or to sophistically handle the errors from a frontend application. So let's dive into how to improve this. Error handling is described in the GraphQL specification and is part of the default structure of any GraphQL response. This response consists of 3 fields: The simplest type of error that you can get is when you in example try to use an operation that's not present in the schema of your GraphQL API. Suppose we have an API that serves as the backend for a music application. Using queries and mutations, you will be able to view tracks, add playlists, and save tracks to playlists that you've created. One of the operations for that API is a mutation to add a track to a playlists, which is called saveTrackToPlaylist . But suppose we make a mistake when spelling the mutation in the GraphQL playground. What would happen? The server will throw a default GraphQL error, as the misspelled mutation is not present in the schema: The response object has the previously mentioned error field and a message stating the error: Cannot query field \"saveTrrackToPlaylist\" on type \"Mutation\". Did you mean \"saveTrackToPlaylist\"? . As you can see GraphQL graciously prevents you in sending non-existing operations to the server. Similar errors are thrown when your operation variables or requested fields are incorrect. When you have an error that's not related to the GraphQL schema, you would have to throw an error from the resolvers of your GraphQL server. This can simpy be done by throwing an error from the resolver. This would looks something like this for the music application server: In the resolver an error is thrown when the playlist or track that you define for the saveTrackToPlaylist mutation are not present in the database. The error message will again be added to the errors field of the GraphQL response object. The snippet above has been truncated but the actual response in the GraphQL playground is a huge chunk of JSON, which makes it hard to get the important information from that response. Fortunately, the GraphQL specification allows you to add a field called extensions to the error object. To extend the error object, you can either throw a custom Error object or use predefined error methods available in Apollo Server. Apollo Server provides several predefined errors, such as AuthenticationError , ForbiddenError , and UserInputError , as well as the general ApolloError . These errors make it easier for you to debug and read errors from the GraphQL server. Handling errors this way works especially well when you're using Apollo to create your GraphQL server, but there are more declarative ways of returning errors to the client. One way of doing so is by adding errors as data. This approach has several advantages: To add errors to your data, you need to use the Union type (a.k.a. Result ) in your GraphQL schema. Also, the logic in the resolver is rewritten so that next to the result or error for the operation you also need to return a type for it. This allows you to send the previous mutation in the following way, which has different payload types based on the return of the resolver. The mutation saveTrackToPlaylist now has three different payloads depending on the result of the resolver. The payload SaveTrackSuccess returns the playlist and tracks details when the operation is successful, while the SaveTrackPlaylistError and SaveTrackError are retuned when an error occurs. More implementations for error handling in GraphQL and the full source code are available it the book Fullstack GraphQL .