Handle errors

May 9, 2023 MrAnyx 3 min de lecture
Intermédiaire

Until now, the errors we had were in HTML format.

To create a consistent API, this format is not ideal. It would be more interesting to return JSON even when it is an error.

Creating the normalizer

To do this, we will use a Normalizer. As mentioned in the documentation, a normalizer allows to transform any data into an associative list. In our case, we will create a normalizer to transform exceptions into a list that will be managed by Symfony.

Let's start by creating a new file called src/Normalizer/ErrorNormalizer.php. In this file we will add the following content that we will explain next.

// src/Normalizer/ErrorNormalizer.php

namespace App\Normalizer;

use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

class ErrorNormalizer implements NormalizerInterface
{
    public function normalize($exception, string $format = null, array $context = []): array
    {
        return [
            'message' => $context['debug'] ? $exception->getMessage() : 'An error occured',
            'status' => $exception->getStatusCode(),
            'trace' => $context['debug'] ? $exception->getTrace() : [],
        ];
    }

    public function supportsNormalization($data, string $format = null, array $context = []): bool
    {
        return $data instanceof FlattenException;
    }
}

The normalize method allows to transform our object into a list. As for the supportsNormalization method, it allows to define the elements that will be normalized with the previous method.

For security reasons, the error message and the stacktrace will be displayed only when the application is in debug mode, in other words, in dev mode. This way, when our api is in production, the error details will not be accessible.

Changing the response format

Also, in order to "activate" our normalizer, we will change the default format of the responses. Instead of using an HTML format, we will use the JSON format.

To do this, it's very simple, just add a new format parameter to the Route attribute of our controller.

// src/Controller/TodoController.php

#[Route("/api", "api_", format: "json")]
class TodoController extends AbstractController
{
    // ...
}

That's it. Now, if we generate an error while trying to read the information of a todo that does not exist, our error will be serialized in JSON format using the format that we have defined.

Our normalizer is not restricted to the JSON format. Indeed, if we want to change the format to XML, the error format would also be updated to follow the format we have defined.

In summary

In this lesson we have seen one of the methods to change the error format. Indeed, we could have used an EventSubscriber, however this method allows to create only one error format (only JSON or only XML for example). The advantage of the normalizer is that it is adaptive. As we mentioned, we can very simply change the format of the errors.

Cette œuvre est mise à disposition selon les termes de la licence Licence Creative Commons