I'm trying to upgrade my project to FOSRestBundle 2.8 but can't figure out how to handle errors correctly.
Previously we were relying on the ExceptionListener which is now deprecated. The call stack went like this:
/src/ApiBundle/Component/Serializer/JsonExceptionNormalizer.php:66
/src/ApiBundle/Component/Serializer/JsonExceptionNormalizer.php:45
/vendor/jms/serializer/src/GraphNavigator/SerializationGraphNavigator.php:192
/vendor/jms/serializer/src/Serializer.php:249
/vendor/jms/serializer/src/Serializer.php:162
/vendor/friendsofsymfony/rest-bundle/Serializer/JMSSerializerAdapter.php:62
/app/cache/test/ContainerS2qAfcv/JMSSerializerAdapter_a5dd94b.php:27
/vendor/friendsofsymfony/rest-bundle/View/ViewHandler.php:458
/vendor/friendsofsymfony/rest-bundle/View/ViewHandler.php:424
/vendor/friendsofsymfony/rest-bundle/View/ViewHandler.php:310
/vendor/friendsofsymfony/rest-bundle/Controller/ExceptionController.php:67
/vendor/symfony/http-kernel/HttpKernel.php:158
/vendor/symfony/http-kernel/HttpKernel.php:80
/vendor/symfony/http-kernel/EventListener/ErrorListener.php:60
/vendor/friendsofsymfony/rest-bundle/EventListener/ExceptionListener.php:81
In the JsonExceptionNormalizer I have some custom logic to add validation errors into the final json when the thrown exception contains symfony/validator violations.
What extension point can I use now when the ExceptionListener is deprecated? Or what can I use to trigger my current ViewHandler -> JMSSerializerAdapter -> JsonExceptionNormalizer logic?
FosRestBundle did deprecate the ExceptionListener because Symfony has a new component called ErrorHandler which is used instead of that.
If you disable the exception listener you should make sure you disable also the deprecated ExceptionController of Symfony, FosRest should throw you an error if you forgot that here.
If you did correctly disable the deprecated symfony exception controller the following way:
twig:
exception_controller: null
The symfony error handler component should handle this correctly.
I'm not very familiar with implementation maybe @xabbuh can provide there more, whats best to extend it. In @sulu I did keep it simple and decorated the FosRest Error Normalizer to change the output:
https://github.com/sulu/sulu/pull/4798/files#diff-a097bf1329bf027e774b48ddb459fb5e
https://github.com/sulu/sulu/pull/4798/files#diff-4f4ac11710f21c2c11567806aff5a1a5
Maybe this helps you.
Your FlattenExceptionNormalizer implements Symfony\Component\Serializer\Normalizer\NormalizerInterface. In my case however I'm not using the symfony/serializer component - I'm using JMS Serializer instead. So sadly this doesn't help me. :-(
For the JMS Serializer we have the FlattenExceptionHandler. You then need an ErrorRenderInterface implementation that is able to leverage the JMS serializer which you can register with the serializer_error_renderer option:
fos_rest:
exception:
serializer_error_renderer: true
@xabbuh I don't understand... am I supposed to use a custom implementation of serializer_error_renderer? If so why is the option boolean? How do I make rest bundle aware of my implementation?
I did find FlattenExceptionHandler myself too but it only has 2 formats but I need to use my own formatting logic...
@enumag As I see the service just call the serializer: https://github.com/FriendsOfSymfony/FOSRestBundle/blob/ec65a37d4ae87040786f6c046dedc5a5c494278f/ErrorRenderer/SerializerErrorRenderer.php#L69
so you can just create a JMS Serialization Subscriber or define serialization configuration for your exception.
@enumag When you enable that option we will register an error renderer for you which is able to use the Serializer abstraction that FOSRestBundle provides. Thus it will work with Symfony serializer as well as JMS serializer. And if the format provided by the FlattenExceptionHandler doesn't fit your needs, you can indeed register your own handler as the error renderer doesn't do anything special but just uses the serializer.
The SerializerErrorRenderer is never called even though I have it enabled. Do I need to enable something else too? Where is it supposed to be called? Currently the exception is just handled by FlattenExceptionHandler...
Do you have some custom error/exception controller configured (using framework.error_controller or twig.exception_controller)?
Yes, I do...
But it extends the default \Symfony\Component\HttpKernel\EventListener\ErrorListener. I only changed the duplicateRequest method a little bit.
I don't see where the ErrorListener is related here. You will need to make sure that Symfony uses the new ErrorController which will call the error renderer (which should be our one) from where the serializer is called then.
parameters:
framework.error_controller: AppBundle\EventListener\ExceptionListener
Then you will need to make sure that your own exception listener uses the error renderer.
Actually I'm trying to use custom implementation of SubscribingHandlerInterface instead. But somehow the exception is passed to FlattenExceptionNormalizer instead of FlattenExceptionHandler even though I'm not using symfony/serializer. Also it goes through SerializerErrorRenderer even though I set:
fos_rest:
exception:
serializer_error_renderer: false
Oh... it's not the SerializerErrorRenderer from this bundle but \Symfony\Component\ErrorHandler\ErrorRenderer\SerializerErrorRenderer...
Anyway, how do I make the exception to be handled by FlattenExceptionHandler instead of FlattenExceptionNormalizer?
Can you please show the output of bin/console debug:config framework?
Looks like I managed to fix it...
fos_rest:
exception:
enabled: true
exception_listener: false
serializer_error_renderer: true
serialize_exceptions: false
and updated my JsonExceptionNormalizer:

@enumag That's good news. Do you think we could have worded some upgrade notes more explicitly to make this easier to work?
@xabbuh I kinda feel like my way might not be optimal... In my opinion your documentation should contain a recommended way for custom exception formatting when you want the API to show validation errors. Then the upgrade notes should point to this section as a recommended way to replace the deprecated error_listener / error_controller options.
@xabbuh is it really good way to handle those exception messages as @enumag has shown in https://github.com/FriendsOfSymfony/FOSRestBundle/issues/2200#issuecomment-629150462 ?
As for me, it seems kinda strange that I need to use JsonExceptionNormalizer instead of ExceptionController. I think it is just two different abstractions. What should I do if I want to use ExceptionController ?
Most helpful comment
Looks like I managed to fix it...
and updated my JsonExceptionNormalizer: