1

I try handle all excpetions (Symfony 5) via official documentation: https://symfony.com/doc/current/controller/error_pages.html#overriding-error-output-for-non-html-formats

I want serialize all exception to JSON format. I read solution for similar problem in this topic: How to format all HttpExceptions as json in symfony5? but doesn't resolve my problem.

There my files: src/Controller/ShowController.php

<?php

namespace App\Controller;

use App\Component\ShowResponseHandlerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;

class ShowController extends AbstractController
{
    /**
     * @Route("/show/{file}", name="show", requirements={"file"=".+"})
     */
    public function index(string $file, string $storageDirectory): Response
    {
        $absolutePath = $storageDirectory.$file;
        if(!file_exists($absolutePath)) {
            throw new NotFoundHttpException("Resource not exists");
        }

        return new BinaryFileResponse($absolutePath);

    }
}

src/Serializer/ProblemNormalizer.php

<?php
namespace App\Serializer;

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

class ProblemNormalizer implements NormalizerInterface
{

    public function normalize($exception, string $format = null, array $context = [])
    {
        return [
            'success' => false,
            'exception'=> [
                'message' => $exception->getMessage(),
                'code' => $exception->getStatusCode(),
            ]
        ];
    }

    public function supportsNormalization($data, string $format = null)
    {
        return $data instanceof FlattenException;
    }
}

config/services.yaml

services:
_defaults:
    autowire: true      # Automatically injects dependencies in your services.
    autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    App\Serializer\ProblemNormalizer:
        tags: ['serializer.normalizer']

and of course i have installed package symfony/serializer

composer show -i | grep "symfony/serializer"

symfony/serializer                 v5.2.9  Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON

What I'm doing wrong or what is not configured? It always return html output.

Update

Console output for:

symfony console debug:container | grep normalizer
  Symfony\Component\Serializer\Normalizer\DenormalizerInterface                alias for "serializer"                                                                     
  Symfony\Component\Serializer\Normalizer\ObjectNormalizer                     alias for "serializer.normalizer.object"                                                   
  Symfony\Component\Serializer\Normalizer\PropertyNormalizer                   alias for "serializer.normalizer.property"                                                 
  maker.auto_command.make_serializer_normalizer                                Symfony\Bundle\MakerBundle\Command\MakerCommand                                            
  maker.maker.make_serializer_normalizer                                       Symfony\Bundle\MakerBundle\Maker\MakeSerializerNormalizer                                  
  serializer.denormalizer.array                                                Symfony\Component\Serializer\Normalizer\ArrayDenormalizer                                  
  serializer.denormalizer.unwrapping                                           Symfony\Component\Serializer\Normalizer\UnwrappingDenormalizer                             
  serializer.normalizer.constraint_violation_list                              Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer                  
  serializer.normalizer.data_uri                                               Symfony\Component\Serializer\Normalizer\DataUriNormalizer                                  
  serializer.normalizer.dateinterval                                           Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer                             
  serializer.normalizer.datetime                                               Symfony\Component\Serializer\Normalizer\DateTimeNormalizer                                 
  serializer.normalizer.datetimezone                                           Symfony\Component\Serializer\Normalizer\DateTimeZoneNormalizer                             
  serializer.normalizer.flatten_exception                                      Symfony\Component\Messenger\Transport\Serialization\Normalizer\FlattenExceptionNormalizer  
  serializer.normalizer.form_error                                             Symfony\Component\Serializer\Normalizer\FormErrorNormalizer                                
  serializer.normalizer.json_serializable                                      Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer                         
  serializer.normalizer.mime_message                                           Symfony\Component\Serializer\Normalizer\MimeMessageNormalizer                              
  serializer.normalizer.object                                                 Symfony\Component\Serializer\Normalizer\ObjectNormalizer                                   
  serializer.normalizer.problem                                                Symfony\Component\Serializer\Normalizer\ProblemNormalizer                                  
  serializer.normalizer.property                                               Symfony\Component\Serializer\Normalizer\PropertyNormalizer                                 
  serializer.normalizer.uid                                                    Symfony\Component\Serializer\Normalizer\UidNormalizer                                      

 // To search for a specific service, re-run this command with a search term. (e.g. debug:container log) 
Lubski
  • 11
  • 2

1 Answers1

2

Try to remove App\Serializer\ProblemNormalizer from config/services.yaml. Recheck container for normalizers again symfony console debug:container | grep normalizer. Normally you should see your normalizer in the list without any config (Symfony recognizes it by NormalizerInterface). Test with curl http://localhost:8000/show/foo.doc -H "Accept: application/json"

ias
  • 21
  • 1
  • 1
    Thanks!. Reason was. 1. Not needed service: App\Serializer\ProblemNormalizer 2. Second was. I did not send header with accepting response as json: Accept: application/json. Now I have nice response in json format {"success":false,"exception":{"message":"Resource not exists","code":404}} – Lubski May 29 '21 at 08:36
  • Consider to use `$context`: e.g. limit response messages, `if($context['debug']) {$message = $exception->getMessage()} else{ $message = $exception->getStatusText()}`, you may also add extra data from original exception or translate your message accordingly based on `$context['exception']`. – ias May 31 '21 at 08:50