Return JSON based on “Accept: application/json” from a Symfony2 controller without modifying each controller action
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.
Josh
Updated on March 09, 2020Comments
-
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.