Search code examples
phpsymfonyfosrestbundlecontent-negotiation

How can I serve HTML and JSON requests from the same route, using Symfony 2 and FOSRestBundle, using headers in addition to the _format?


I am attempting to serve content in both html and json formats (I also want to eventually allow for xml as well) using Symfony and the FOSRestBundle (ver. 1.3). I have been successful at serving different content for routes using the _format parameter, e.g.:

  • /foo.json will result in a JSON response,
  • and /foo will result in an HTML response.

Is there any way to reconcile (on the same host!) the same content negotiation above using something other than _format, for example the Content-Type or Accept headers?

I've looked at the Format Listener but I think that I have a fundamental misunderstanding of how to configure it.


Given the defined route:

<route id="foo" pattern="/foo.{_format}" methods="GET">
    <default key="_controller">FooBundle:Foo:get</default>
    <default key="_format">html</default>
</route>

... for the following action:

public function getAction(Request $request)
{
    $view = View::create()
        ->setData(array('greeting' => 'hello world'))
        ->setFormat($request->getRequestFormat('html'))
        ->setTemplate('FooBundle:Foo:get.html.twig');
    return $this->get('fos_rest.view_handler')->handle($view);
}

... and the following FOSRestBundle configuration (snippet):

fos_rest:
  ...
  format_listener: true

I am required to specify the _format parameter in the request if I want negotiated content in a format other than the default (html), as above.

However, if I specify the following rules for the format listener:

fos_rest:
  format_listener:
    rules:
      - { path: '^/', priorities: ['json'], fallback_format: ~, prefer_extension: false }
      - { path: '^/', priorities: ['html', '*/*'], fallback_format: html, prefer_extension: true }

The browser request returns my responses as Content-Type: application/json but the actual content is the text/html content rather than the serialized JSON. If I explicitly specify the Accept header though on the request as Accept: text/html the response I receive is has a content type header of Content-Type: text/html.

Any help would be greatly appreciated!


Solution

  • If you want Content negotiation based on Content-type header you need BodyListener instead of FormatListener. Read the documentation.