Return JSON based on “Accept: application/json” from a Symfony2 controller without modifying each controller action

24,599

Solution 1

As a generic idea, in case you want to avoid using 3rd party bundles, you may subscribe to the kernel.response event and play with the Response there, just in one common place.

Something like:

//services.yml

services:
  my.kernel.listener:
    class: Acme\Bundle\AppBundle\EventListener\MyKernelListener
    tags:
      - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }

// MyKernelListener.php

class MyKernelListener
{
    public function onKernelResponse(FilterResponseEvent $event)
    {
        $response = $event->getResponse();
        $request = $event->getRequest();
        // ... your logic ...
    }
}

Solution 2

The bundle you are looking for is the FOSRestBundle.

You can have it serve JSON based on Accept header or adding _format to your routes ... highly configurable.

Works nice with JMSSerializerBundle.

Share:
24,599
Josh
Author by

Josh

Updated on March 09, 2020

Comments

  • Josh
    Josh about 4 years

    I'm working on an app that I want to offer both JSON and HTML responses. Here's an example action method:

    /**
     * Lists all Boards entities.
     *
     * @Route("/", name="boards")
     * @Method("GET")
     * @Template()
     */
    public function indexAction()
    {
        $em = $this->getDoctrine()->getManager();
    
        $entities = $em->getRepository('ScrumBoardServiceBundle:Boards')->findAll();
    
        $acceptHeader = strtolower($this->getRequest()->headers->get('Accept'));
        if ($acceptHeader === 'application/json') {
            $serializer = new Serializer(array(new GetSetMethodNormalizer()), array('json' => new
                    JsonEncoder()));
            $response = $serializer->serialize(array('success' => true, 'data' => array(
                    'entity' => $entities,
            )), 'json');
            $result = new Response($response, 200, array('Content-Type' => 'application/json'));
        } else {
            $result = array(
                'entities' => $entities,
            );
        }
    
        return $result;
    }
    

    This works fine. If you send in an HTTP Accept header that is exactly application/json, you will get JSON back. Otherwise, you get the usual hTML view.

    This works fine, but I've got dozens of actions. I'd rather not repeat myself. I'm working on refactoring this code into something a little more generic... but I'm also wondering if this problem has already been solved by an existing Symfony2 bundle. Maybe something with annotations? Or a config setting? I haven't been able to find anything so far. But I am so new to Symfony I could very easily be missing something.