I am trying to setup my application so the same action can return responses for both web and api. This working great but sometimes the action is only required for the website and not the api. I am looking for a way to enable/disable this functionality per action/controller.
I've created two demo actions to test with, but have been unable to make one not respond on the api url.
Website is accessible via domain.com
Api is accessible via api.domain.com - All requests to the api are formatted as json using the format listener in the config
- { path: '^/', host: 'api.domain.dev', priorities: ['json'], fallback_format: ~, prefer_extension: false }
The first action(indexAction) works fine returning both HTML and Json depending on which domain you use. The problem is with the second action(testAction) and I want this to only work on the website domain. When visiting api.domain.com/company-test the response is the template HTML with the content-type header set to application/json.
Is there a way to make this return an error(404?) when the JSON version is not available and @Template is being used?
Test Actions
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
/**
* Get a list of companies
*
* @Rest\Get("/company")
* @Rest\View(
* template = "CompanyBundle:Company:index.html.twig",
* templateVar = "companies",
* statusCode = 200,
* )
*
* @ApiDoc(
* description=""
* )
*/
public function indexAction() {
$em = $this->getDoctrine()->getManager();
$companies = $em->getRepository('CompanyBundle:Company')->findAll();
$view = View::create();
$view->setData($companies);
$view->setTemplateData(['extraData' => 'Hello World!']);
return $view;
}
/**
* Get a list of companies
*
* @Route("/company-test")
*
* @ApiDoc(
* description=""
* )
*
* @Template(
* template="CompanyBundle:Company:index.html.twig"
* )
*/
public function testAction() {
$em = $this->getDoctrine()->getManager();
$companies = $em->getRepository('CompanyBundle:Company')->findAll();
return [
'companies' => $companies,
'test-test' => 'Hello World!'
];
}
I think you can extend TemplateListener from SensioFrameworkExtraBundle and modify "onKernelView" https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/EventListener/TemplateListener.php#L77
Create you own listener as MyBundle\EvetListener\MyListener.php that extends original TemplateListener, then you can whole onKernelView method and chanage https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/EventListener/TemplateListener.php#L83 to
if (null === $template) {
return;
} elseif($this->getRequest()->getHost() == $this->container->getParameter('api_domain')) { // %api_domain% should be filled at parameters.yml
$event->setResponse(new JsonResponse(NULL, Response::HTTP_NOT_FOUND)); // don't forget to add "use Symfony\Component\HttpFoundation\JsonResponse"
return;
}
override the service parameter https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/Resources/config/view.xml#L8
as
<parameters>
<parameter key="sensio_framework_extra.view.listener.class">MyApp\EventListener\MyListener</parameter>
</parameters>
or via yml if you use yml instead of xml for services config