NodeJS GraphQL: Handling GraphQL Errors in NodeJS #5

In this chapter, you will understand how to handle GraphQL errors in your application.



All applications fail, and GraphQL is no different. Some clients may ask for information that’s not available or execute a forbidden action. In this section, you’ll learn how to handle errors in your GraphQL API.


So lets get started with error handling in GraphQL!
. . .

GraphQL Error Types

There are a plethora of errors that a client can encounter when querying a GraphQL Server. Whether it’s a query, mutation, or subscription, they all fall into 6 types:
  1. Server problems (5xx HTTP codes, 1xxx WebSocket codes)
  2. Client problems e.g. rate-limited, unauthorized, etc. (4xx HTTP codes)
  3. The query is missing/malformed
  4. The query fails GraphQL internal validation (syntax, schema logic, etc.)
  5. The user-supplied variables or context is bad and the resolve/subscribe function intentionally throws an error (e.g. not allowed to view requested user)
  6. An uncaught developer error occurred inside the resolve/subscribe function (e.g. poorly written database query)
So, which of these errors is critical enough to ignore all the data?
  • Numbers 1–3 for sure, since they occur before GraphQL even gets called.
  • Number 4, too, it calls GraphQL, but only receives errors in response.
  • For 5–6, GraphQL responds with both partial data and an array of errors. Some would conflate type 5 with type 2, for example, running out of query “points” (like what GitHub does) could constitute an HTTP 429 (too many requests). But at the end of the day, the simplest answer is the best:
If GraphQL gives you a result with data, even if that result contains errors, it is not an error.
. . .

Schema Errors

Being a language with a strong type system, GraphQL can predetermine if a query is valid. All the fields from queries and mutations have a strong type, so requesting and inputting wrong data will generate an error. Try it out! In the human query, ask for the age field and see how GraphQL returns back an error:
If you want to know more about the graphql type system you can refer this post
. . .

Handling GraphQL Errors

All applications fail, and GraphQL is no different. Some clients may ask for information that’s not available or execute a forbidden action. On the application level, you can use the inbuilt GraphQL error in apollo server for raising the exception in your application.

Apollo GraphQL Server provides a collection of predefined errors, including AuthenticationError, ForbiddenError, UserInputError, and a generic ApolloError.

These errors are designed to enhance errors thrown before and during GraphQL execution, making it easier to debug your Apollo Server integration and enabling clients to take specific actions based on an error.

When an error occurs in Apollo Server both inside and outside of resolvers, each error inside of the errors array contains an extensions object that contains the information added by Apollo Server.

We can import the inbuilt errors provided by the apollo-server to throw GraphQL error in our application
const { UserInputError } = require('apollo-server');

If you have not installed the apollo-server dependency, run the below command to get it
yarn add apollo-server

We need to validate the user input, what happens when the user has provided the wrong input, something went wrong at the server, database failed, etc. We need to provide proper errors so that consumers of API can understand the errors.

We will update the person resolver, we will throw the error if we could not find the person with the given ID, so let's go ahead and update the resolver

const resolvers = {
Query: {
async person(parent, args ) {
// #1
const id = args.id
// #2
person = Persons.find(person => person.id === id)
if (person === null || this.person === undefined){
// #3
throw new UserInputError('could not find any user with given id', {
// #4
data: args
});
}
return this.person
},
}
}

Let's walk through the comments to understand the code
  1. We are getting the user id from arguments
  2. We are filtering the users with the id
  3. If we could not find any person with the given id we are throwing the GraphQL error
  4. The user input is passed to the errors array, it will be available into the extensions object, it helps in debugging

Similarly, we can throw the AuthenticationError, ForbiddenError, UserInputError, and a generic ApolloError depending upon the application state and error type
. . .

Testing the Query

Go ahead and restart your server so you can test the new API operations. Here is a sample query you can send through the Playground to test error handling:
{
person(id: 100) {
id
name
mass
height
homeworld
}
}

As we don't have any person with the userID 100, it will throw the graphql error, you can see below how the error looks like

We have just looked at the surface of error handling in your graphql server, but it can be modified according to your requirements You can explore about apollo-server errors here.
. . .
In the next tutorial, we will add JWT authentication to secure the GraphQL API.


Never miss a post from Gufran Mirza, when you sign up for Ednsquare.