Errors and Exceptions

When error occurs in GraphQL, the server adds an errors entry in the response. Here is an example

{
    "errors": [
        {
            "message": "Wished price was not found by id: some-id",
            "locations": [
                {
                    "line": 2,
                    "column": 3
                }
            ],
            "path": [
                "wishedPrice"
            ]
        }
    ]
}

You can read more about GraphQL errors in the official spec.

In most cases the HTTP status code will also reflect the error condition. So for example it will be 404 in case something was not found.

Exceptions in your module

The graphql-base module provides the following exceptions you can use or extend from

Class Category Description HTTP Status code
InvalidLogin permissionerror Thrown when we have an invalid login 401
InvalidToken permissionerror Thrown when a token is invalid 403
NotFound requesterror Thrown when a record was not found 404
Exists requesterror Thrown when a record exists (when we want to register already registered customer) 400
OutOfBounds requesterror Thrown when values are out of bounds 400

Exception to GraphQL Error

The GraphQL modules are build using GraphQLite, which requires graphql-php. Here you can see how graphql-php handles errors.

In short: If you want the consumer to see the message of your exception, it needs to implement the GraphQL\Error\ClientAware interface.

HTTP Status code

If you want to change the HTTP status code in your custom exception, you have to implement OxidEsales\GraphQL\Base\Exception\HttpErrorInterface

Error categories

In the error response you might want to see a category entry, which describes the category of the error. You can use OxidEsales\GraphQL\Base\Exception\ErrorCategories class, which defines several error categories.

Example

Here is an example of a custom exception which tells us that a product was not found. It is part of the graphql-storefront module.

<?php

declare(strict_types=1);

namespace OxidEsales\GraphQL\Storefront\Product\Exception;

use OxidEsales\GraphQL\Base\Exception\NotFound;

use function sprintf;

final class ProductNotFound extends NotFound
{
    public static function byId(string $id): self
    {
        return new self(sprintf('Product was not found by id: %s', $id));
    }
}

Here is an example of an exception when customer’s password does not match the requirements:

<?php

declare(strict_types=1);

namespace MyVendor\MyModule\Record\Exception;

use Exception;
use GraphQL\Error\ClientAware;
use OxidEsales\GraphQL\Base\Exception\ErrorCategories;
use OxidEsales\GraphQL\Base\Exception\HttpErrorInterface;

final class PasswordMismatchException extends Exception implements ClientAware, HttpErrorInterface
{
    public function getHttpStatus(): int
    {
        return 403;
    }

    public function isClientSafe(): bool
    {
        return true;
    }

    public function getCategory(): string
    {
        return ErrorCategories::REQUESTERROR;
    }

    public static function byOldPassword(): self
    {
        return new self('Old password does not match our records');
    }

    public static function byLength(): self
    {
        return new self('Password does not match length requirements');
    }
}

In this example you can see the usage of ClientAware, HttpErrorInterface and ErrorCategories.