Easy Hot Chocolate GraphQL Error Handling

Published 2020-06-05

A cozy cup of hot chocolate.

Photo by Vitaly Eroshenko on Unsplash

Hot Chocolate is a platform to build GraphQL APIs in .NET Core and .NET Framework. In this article I'll go over an easy and consistent way to handle errors.

GraphQL Error Theory 📢

First off, GraphQL errors are a little different than REST API errors.

In REST to handle an error, you would carefully set an HTTP status code on the response and if needed more details could be added to the response body.

REST response example: GET /users/123 where user 123 does not exist:

// httpStatusCode = 404 not found
{
  "error": {
    "message": "user not found",
    "code": "someErrorCode"
  }
}

With GraphQL, a response will only have a 200 OK HTTP status code. In short, the theory is that HTTP status codes are transport layer concerns and if the transport succeeded (regardless of server-side issues) then respond with 200 OK.

Error details are only included in the body of the response as an array of errors.

Errors in Hot Chocolate ☕

By default, throwing an error in a query, mutation, or resolver will cause Hot Chocolate to create an instance of IError with the message of Unexpected Execution Error.

Consider this code for attempting to login a user (AppException is a custom exception, nothing fancy):

var applicationUser = await GetUserByEmail(email);

if (applicationUser == null)
{
    throw new AppException($"Cannot find user with email {email}");
}

When the user is not found, the server will respond with:

{
  "errors": [
    {
      "message": "Unexpected Execution Error",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],

The default Unexpected Execution Error message can be overridden with an Error Filter to transform the IError instance.

Inherit from IErrorFilter and do your transformations in the OnError method. Access to the thrown exception is in error.exception.

    public class GraphQLErrorFilter : IErrorFilter
    {
        public IError OnError(IError error)
        {
            return error.WithMessage(error.Exception.Message);
        }
    }

Then register the filter in Startup.cs

services.AddErrorFilter<GraphQLErrorFilter>();

A meaningful message is now in the message field:

{
  "errors": [
    {
      "message": "Cannot find user with email test@test.com",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],

Happy coding 👩‍💻


#asp.net core#graphql