I am working in a Restful API using Symfony2 and FOSRestBundle. I have read view layer docs but is not clear to me how to handle output for API. What I want to achieve is simple: display or return or output the result as valid JSON. This is what I have at controller:
<?php
/**
* RestAPI: Company.
*/
namespace PDI\PDOneBundle\Controller\Rest;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Request\ParamFetcherInterface;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\Get;
class CompanyRestController extends FOSRestController
{
/**
* Gets all companies.
*
* @return array
*
* @ApiDoc(
* resource = true,
* https = true,
* description = "Gets all companies",
* statusCodes = {
* 200 = "Returned when successful",
* 400 = "Returned when errors"
* }
* )
* @Get("/api/v1/companies")
*
*/
public function getCompaniesAction()
{
$response = array();
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('PDOneBundle:Company')->findAll();
if ($entities) {
foreach ($entities as $entity) {
$response['companies'][] = [
'id' => $entity->getId(),
'createdAt' => $entity->getCreatedAt(),
'updatedAt' => $entity->getUpdatedAt(),
'name' => $entity->getName(),
'logo_url' => $entity->getLogoUrl(),
'division' => $entity->getDivision(),
'inactive' => $entity->getInactive(),
];
}
$response['status'] = 'ok';
} else {
$response['status'] = 'error';
}
return $response;
}
}
If I try this URL: /app_dev.php/api/v1/companies.json
I got 404 error:
{"code":404,"message":"No route found for \"GET\/api\/v1\/companies.json\""}
If I try this URL: https://reptool.dev/app_dev.php/api/v1/companies
error turns on:
Unable to find template "". 500 Internal Server Error - InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException »
I've also check FOSRestBundleByExample but didn't get much help.
What I am missing here? How do I achieve what I need? Any advice?
FOSRest Config
I forgot to add the FOSRestBundle at config.yml
:
#FOSRestBundle
fos_rest:
param_fetcher_listener: true
body_listener: true
format_listener:
rules:
- { path: ^/, priorities: [ json, html ], fallback_format: ~, prefer_extension: true }
media_type:
version_regex: '/(v|version)=(?P<version>[0-9\.]+)/'
body_converter:
enabled: true
validate: true
view:
mime_types:
json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
view_response_listener: 'force'
formats:
xml: false
json: true
templating_formats:
html: true
exception:
codes:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
messages:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
allowed_methods_listener: true
access_denied_listener:
json: true
I feel your pain. I had troubles getting started as well. One important place to start is the config. Here's what I use in my implementation.
fos_rest:
param_fetcher_listener: true
view:
mime_types:
json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
view_response_listener: 'force'
formats:
xml: false
json: true
templating_formats:
html: true
format_listener:
rules:
- { path: ^/, priorities: [ json, html ], fallback_format: ~, prefer_extension: true }
media_type:
version_regex: '/(v|version)=(?P<version>[0-9\.]+)/'
exception:
codes:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
messages:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
allowed_methods_listener: true
access_denied_listener:
json: true
body_listener: true
In the format_listener
if you want JSON to be the default response, make sure it's set first in priorities. Otherwise your header will need to include Accept: application/json
every time. This may be why you're getting a twig error as it's trying to use twig to render an HTML output.
Also, make sure you have a serializer like http://jmsyst.com/bundles/JMSSerializerBundle installed and included in your AppKernal.
In your controller I found it easiest to extend the FOSRestController like you did, but also return a view object instead of creating the array yourself. The serializer will handle all of that for you.
/**
* RestAPI: Company.
*/
namespace PDI\PDOneBundle\Controller\Rest;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Request\ParamFetcherInterface;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\Get;
class CompanyRestController extends FOSRestController
{
/**
* Gets all companies.
*
* @return array
*
* @ApiDoc(
* resource = true,
* https = true,
* description = "Gets all companies",
* statusCodes = {
* 200 = "Returned when successful",
* 400 = "Returned when errors"
* }
* )
* @Get("/api/v1/companies")
*
*/
public function getCompaniesAction()
{
$response = array();
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('PDOneBundle:Company')->findAll();
if(!$entities)
{
return $this->view(null, 400);
}
return $this->view($entities, 200);
}
}
I hope this helps a little.