I have configured FOSRestBundle as following:
#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
And I have this at controller:
namespace PDI\PDOneBundle\Controller\Rest;
use FOS\RestBundle\Controller\FOSRestController;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\Get;
class RepresentativeRestController extends FOSRestController
{
/**
* Get all representatives.
*
* @return array
*
* @ApiDoc(
* resource = true,
* https = true,
* description = "Get all representatives.",
* statusCodes = {
* 200 = "Returned when successful",
* 400 = "Returned when errors"
* }
* )
* @Get("/api/v1/reps")
*/
public function getRepsAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('PDOneBundle:Representative')->findAll();
if(!$entities)
{
return $this->view(null, 400);
}
return $this->view($entities, 200);
}
}
But when I try the following URL app_dev.php/api/v1/reps
I got this error:
Unable to find template "". 500 Internal Server Error - InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException »
I expect that API return a well formed JSON as the following example:
{
"id":"30000001",
"veeva_rep_id":"0055648764067SwzAAE",
"display_name":"John Know",
"avatar_url":"http://freelanceme.net/Images/default%20profile%20picture.png",
"rep_type":"VEEVA",
"username":"[email protected]",
"first":"John",
"last":"Know",
"title":"Sales Representative",
"phone":"800-555-1212",
"email":"[email protected]",
"territory_id":"200454001",
"inactive":"no",
"total_contacts":"6",
"total_shares":"0",
"totalViews":"0",
"lastLoginAt":"2015-05-05 15:45:57",
"lastVeevaSyncAt":"2015-05-05 15:45:57",
"createdAt":"2015-05-05 15:45:57",
"updatedAt":"2015-05-05 15:45:57"
}
Is not FOSRestBundle configured for return JSON? Why still asking for Twig template? How can I fix this?
First test:
As @Jeet suggest me I have tried using Postman (is the same as the extension he told me) and after set the header Content-Type
to application/json
the error turns into this
Malformed JSON
so, the FOSRestBundle is not setting up headers as should be and controller is not returning a valid JSON, how do I fix those ones?
Second test:
As suggested by @Jeet I run this test:
/**
* Get all representatives.
*
* @return array
*
* @ApiDoc(
* resource = true,
* https = true,
* description = "Get all representatives.",
* statusCodes = {
* 200 = "Returned when successful",
* 400 = "Returned when errors"
* }
* )
* @Get("/api/v1/reps")
* @View()
*/
public function getRepsAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('PDOneBundle:Representative')->findAll();
$temp = array("1", "2", "3");
$view = $this->view($temp, Codes::HTTP_OK);
return $this->handleView($view);
}
And still the same issue:
Unable to find template "". 500 Internal Server Error - InvalidArgumentException 3 linked Exceptions: Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException »
What else can be wrong here? Did I'm missing something at configuration?
I forgot to add app/config/routing.yml
and src/PDI/PDOneBundle/Resources/config/routing.yml
at first so here them goes, perhaps this is the missing piece on the puzzle and give you a better idea of where the problem comes from:
#app/config/routing.yml
#PDOne
pdone:
resource: "@PDOneBundle/Resources/config/routing.yml"
template:
resource: "@TemplateBundle/Resources/config/routing.yml"
#FOSUserBundle
fos_user:
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
prefix: /
#NelmioApiDocBundle:
NelmioApiDocBundle:
resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
prefix: /api/doc
#SonataAdmin
admin:
resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
prefix: /admin
_sonata_admin:
resource: .
type: sonata_admin
prefix: /admin
#src/PDI/PDOneBundle/Resources/config/routing.yml
pdone:
resource: "@PDOneBundle/Controller/"
type: annotation
prefix: /
Third test:
Definitely something is wrong with request from client side, if I use a tool like Postman
and set proper headers I got the entities as I want, see pic below:
I can't find where the problem is so I desperately need someone's help here because I was already out of ideas
As guys suggested: only Accept header or extension could give you a JSON. Seems like you've got this sorted with Accept header.
In order to use extension you must tell how do you want to set format things in Symfony.
This code should give you an output you want:
namespace RestTestBundle\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use FOS\RestBundle\Controller\Annotations\Get;
class YourController
{
/**
* @Get("/api/v1/reps.{_format}", defaults={"_format"="json"})
* @View()
*/
public function indexAction()
{
return array(
'status' => 'ok',
'companies' => array(
array('id' => 5),
array('id' => 7),
),
);
}
}
Edit1: if you do not want to use a View
class, but pure arrays: do not forget to disallow View handling of SensioExtraBundle
sensio_framework_extra:
view: { annotations: false }
Edit2: If you do not use HTML format and only want to have a json output you can use such fonfiguration:
fos_rest:
# ....
format_listener:
rules:
- { path: ^/, priorities: [ json ], fallback_format: json, prefer_extension: true }
# ....
Explanation why you do see an error "view not found":
TL;DR: your browser send an Accept header that tells FOSRestBundle to output a 'html' variant.
Background: This bundle works mostly with Accept headers, it's a good practice to have all possible output formats that are available: html (you can test your REST API with forms you provide, lists of objects, details of objects easily this way), json, xml. Sometimes even image mime types like image/jpeg, image/png as default or json/xml as a variant (you can use base64 image representation).
Explanation: If you open up a "network" tab of a browser and check out headers it sends you will notice something like: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
which means "use in such order":
If you look close to this is you will see that according to your configuration text/html is one of variants that your configuration has ('html') and */* is another one ('json'), but text/html has a priority of 1, while */* has a priority of 0.8, so text/html matches and FOSRestBundle tries to find a HTML representation and fails.
PS: If you post question multiple times - please make sure you watch for all responses in every thread.
You can give response in two ways
return View::create($entities, Codes::HTTP_OK);
or
$view = $this->view($entities, Codes::HTTP_OK);
return $this->handleView($view)
You can use simply
$view = new View($form);
$view->setFormat('json');
return $this->handleView($view);
FosRestBundle leverages the Accept Header. This means that it returns a response based on what you request. By accessing the route "app_dev.php/api/v1/reps", you are implicitly requesting an html format, so it tries to provide a template.
Does app_dev.php/api/v1/reps.json return what you need?
You should also test app_dev.php/api/v1/reps.xml and expect an xml output
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With