I have a Symfony application app and running, I want to run the FOSRestBundle on a prefix only /api/*
I did some research and found one answer that mentioned using zone
zone:
- { path: ^/api/* }
But I'm getting the following error:
Unable to find template "" (looked into......
This is my config:
fos_rest:
format_listener: false
zone:
- { path: ^/api/* }
view:
view_response_listener: 'force'
formats:
json: true
And this is the controller:
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\View\View;
class APIRestController extends FOSRestController
{
/**
* #Rest\Get("api/gettime")
*/
public function getTimeAction()
{
$restresult = new \DateTime();
$view = View::create($restresult, 200);
return $view;
}
Also:
"friendsofsymfony/rest-bundle": "2.0.0",
"jms/serializer-bundle": "^2.0"
I spent hours reading the documentation and looking online but with no luck, I just keep going in circles!
Fix your configuration:
fos_rest:
format_listener:
rules:
- { path: '^/api', priorities: [ 'json'], fallback_format: json, prefer_extension: true }
zone:
- { path: ^/api/* }
view:
view_response_listener: 'force'
formats:
json: true
Related
I'm implementing FOSUserBundle in my project. I want a basic GET action to return a json object of the ContactList entity.
Controller:
class ContactListController extends FOSRestController
{
use ViewContextTrait;
const DEFAULT_GROUPS = ['organization_list'];
/**
* #ParamConverter("contactList", class="SchemaBundle:ContactList")
* #param ContactList $contactList
* #return Response
*/
public function getAction(ContactList $contactList)
{
return $this->handleView($this->viewWithContext($contactList, Response::HTTP_OK));
}
Trait:
use FOS\RestBundle\Context\Context;
use FOS\RestBundle\View\View;
trait ViewContextTrait
{
public function viewWithContext($data, $statusCode = null, $groups = self::DEFAULT_GROUPS)
{
$context = new Context();
$context->setGroups($groups);
return View::create($data, $statusCode)->setContext($context);
}
}
My config.yml:
fos_rest:
routing_loader:
include_format: false
body_listener:
array_normalizer: fos_rest.normalizer.camel_keys
param_fetcher_listener: true
view:
view_response_listener: 'force'
format_listener:
rules:
- { path: '^/api', priorities: ['json'], fallback_format: json, prefer_extension: false }
The problem: When I call this route via postman (/api/contact-list/1), I always get a {} for my content in the Response object.
This is the dumped response:
What am I missing in order to return the serialized ContactList entity w/ the context group in my Response?
Solution:
First of all, my annotations weren't included. I had to add this to my config.yml:
framework:
serializer:
enabled: true
enable_annotations: true
Next, I forgot I had previously included JMS serializer into my project awhile back. Apparently the ViewHandler for the Rest Bundle has a default order of serializer services that it uses. I ended up having to include this in my config.yml:
fos_rest:
service:
serializer: fos_rest.serializer.symfony
By default, FOSRest was using JMS Serializer which wasn't configured properly.
I'm using Symfony 3.3 and i'm trying to use FOSRestController to make an API.
Here is my config files :
# SensioFrameworkExtra Configuration
sensio_framework_extra:
view: { annotations: false }
# FOSRest Configuration
fos_rest:
format_listener:
rules:
- { path: '^/api', priorities: ['json'], fallback_format: 'json' }
- { path: '^/', stop: true }
view:
view_response_listener: true
Controller :
<?php
namespace AppBundle\Api;
use FOS\RestBundle\Controller\Annotations as REST;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
class MyController extends FOSRestController
{
/**
* #REST\Get("/some-url")
* #REST\View()
*
* #return View
*/
public function getSomethingAction()
{
$view = View::create();
return $view;
}
}
The issue is about the view_response_listener, i'm having this error message :
(1/1) RuntimeException
You must enable the SensioFrameworkExtraBundle view annotations to use the ViewResponseListener.
Routing :
api_something:
type: rest
resource: AppBundle\Api\MyController
The bundle is already installed and added to the AppKernel.php file
Can something help me with this ?
Thanks
Remove your configuration of sensio_framework_extra :
sensio_framework_extra:
view: { annotations: false }
Because the default configuration is annotations: true (you can look at vendor/sensio/framework-extra-bundle/DependencyInjection/Configuration.php)
Let the default configuration of sensio_framework_extra https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html#configuration
You may have forgotten to activate the annotations of serializer in config.yml (https://symfony.com/doc/current/serializer.html#using-serialization-groups-annotations)
I suggest you to try this configs :
#app/config/config.yml
framework:
....
serializer: { enable_annotations: true }
fos_rest:
....
view:
view_response_listener: 'force'
Documentation of FosRestBundle view_response_listener :
http://symfony.com/doc/master/bundles/FOSRestBundle/3-listener-support.html
http://symfony.com/doc/master/bundles/FOSRestBundle/view_response_listener.html
Try to create the directory AppBundle/Api/Controller. And put your MyController.php into it. Your controller will be named
\AppBundle\Api\Controller\MyController
Copy the following code to your main services.yml
sensio_framework_extra.view.listener:
alias: Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener
Source of the solution:
https://github.com/FriendsOfSymfony/FOSRestBundle/issues/1768#issuecomment-340294485
another solution from mentioned source:
in bundles.php the Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle must be located after FOS\RestBundle\FOSRestBundle to work properly
Answer for the same question with Symfony 4.0
routes/rest.yaml Routing configuration
app_admin_users:
type: rest
resource: App\Controller\Api\Admin\User\UsersController
prefix: /api
fos_rest.yaml view response listener enabled
fos_rest:
view:
view_response_listener: true
framework_extra.yaml view annotations enabled
sensio_framework_extra:
view: { annotations: true }
config.yaml imports fos_rest and framework_extra
imports:
- { resource: fos_rest.yaml }
- { resource: framework.yaml }
- { resource: framework_extra.yaml }
I want to execute different actions depending on the client-provided content-type. I've configured 2 controller actions for this:
/**
* #Post("", requirements={"_format": "json"})
*/
public function postJsonAction(Request $request)
{
//
}
/**
* #Post("", requirements={"_format": "csv"})
*/
public function postCsvAction(Request $request)
{
//
}
However, this is not working for me, first action is always executed. What am I doing wrong here?
Here is my fos_rest configuration in the config.yml:
fos_rest:
param_fetcher_listener: true
allowed_methods_listener: true
routing_loader:
default_format: json
include_format: false
view:
mime_types: { 'csv': ['text/csv'], 'xlsx': ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] }
formats:
json: true
csv: true
xlsx: true
format_listener:
rules:
- { path: '^/api', priorities: ['json', 'csv', 'xlsx'], fallback_format: ~, exception_fallback_format: json, prefer_extension: false }
service:
view_handler: app.view_handler
You can configure this in your route. For example, if you are using a yml route configuration.
csv:
path: /article/format/csv/
defaults: { _controller: AppBundle:Article:postCsv }
json:
path: /article/format/json/
defaults: { _controller: AppBundle:Article:postJson }
Then, using JS to change your form action.
if ("csv" === $("#format").val()) {
$('#your_form').attr('action', '/article/format/csv/');
}
else {
$('#your_form').attr('action', '/article/format/json/');
}
I've made a Bundle and a REST controller inside. The "index" method return array in JSON-format, it's ok:
MyBundle/Controller/Api/Rest/BaconController.php
class BaconController extends Controller implements ClassResourceInterface
{
/**
* #var Request $request
* #return array
* #Rest\View
*/
public function cgetAction(Request $request)
{
$mediaType = $request->attributes->get('media_type');
$format = $request->getFormat($mediaType);
my_dump($format);
return array(
array("id" => 1, "title" => "hello",),
array("id" => 2, "title" => "there",),
);
}
}
MyBundle/Resources/config/api/routing_rest.yml
my_api_rest_bacon:
type: rest
resource: "MyBundle:Api/Rest/Bacon"
name_prefix: api_rest_bacon_
prefix: /my/bacon
So, at this point JSON results get returned perfectly:
mysite.com/app_dev.php/api/my/bacon/bacons.json
returns my array.
But now I need to get my controller generate a PDF with the data. So I want it to return PDF document when I call:
mysite.com/app_dev.php/api/my/bacon/bacons.pdf
I've found some half-manuals: RSS view handler, RSS config.ynal, CSV issue with answers. And tried to make something similar:
I've added these lines to
Symfony/app/config/config.yml
framework:
[...some old stuff here...]
request:
formats:
pdf: 'application/pdf'
fos_rest:
body_converter:
enabled: true
format_listener:
rules:
# Prototype array
-
# URL path info
path: ~
# URL host name
host: ~
prefer_extension: true
fallback_format: html
priorities: [html,json]
-
path: ~
host: ~
prefer_extension: true
fallback_format: pdf
priorities: [pdf]
view:
# #View or #Template
view_response_listener: force #true
formats:
json: true
pdf: true
xls: true
html: false
templating_formats:
pdf: false
xls: false
mime_types: {'pdf': ['application/pdf']}
routing_loader:
default_format: html
param_fetcher_listener: true
body_listener: true
allowed_methods_listener: true
services:
my.view_handler.pdf:
class: Lobster\MyBundle\View\PdfViewHandler
my.view_handler:
parent: fos_rest.view_handler.default
calls:
- ['registerHandler', [ 'pdf', [#my.view_handler.pdf, 'createResponse'] ] ]
MyBundle/View/PdfViewHandler.php
namespace Lobster\MyBundle\View;
use FOS\RestBundle\View\View;
use FOS\RestBundle\View\ViewHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class PdfViewHandler
{
public function createResponse(ViewHandler $handler, View $view, Request $request, $format)
{
my_dump('pdf createResponse started');
$pdf = "some pdf";
return new Response($pdf, 200, $view->getHeaders());
}
}
So now when I call
mysite.com/app_dev.php/api/my/bacon/bacons.pdf
I see an error An Exception was thrown while handling: Format html not supported, handler must be implemented and my function my_dump saves to a text file info about file format: it is html, not pdf.
Also pdf createResponse didn't work. Why?
So I've found the solution (I will describe how to enable 2 output formats: PDF and XLS):
1) This section in config.yml is not needed:
framework:
[...some old stuff here...]
request:
formats:
pdf: 'application/pdf'
2) fos_rest.format_listener section in config.yml should look like this:
format_listener:
rules:
-
path: '^/api/my/bacon.*\.xls$'
host: ~
prefer_extension: false
fallback_format: json
priorities: [xls, json]
-
path: '^/api/my/bacon.*\.pdf$'
host: ~
prefer_extension: false
fallback_format: json
priorities: [pdf, json]
-
path: ~
host: ~
prefer_extension: true
fallback_format: html
priorities: [html,json]
3) need to add service section into fos_rest in config.yml
fos_rest:
[...]
service:
view_handler: my.view_handler
4) services root section in config.yml should look like
services:
my.view_handler.xls:
class: Lobster\MyBundle\View\XlsViewHandler
my.view_handler.pdf:
class: Lobster\MyBundle\View\PdfViewHandler
my.view_handler:
parent: fos_rest.view_handler.default
calls:
- ['registerHandler', ['xls', [#my.view_handler.xls, 'createResponse'] ] ]
- ['registerHandler', ['pdf', [#my.view_handler.pdf, 'createResponse'] ] ]
And this is it. Now it works perfect
If files will have different data content, then Controller could as well generate file on their own, returning results in BinaryFileResponse.
No need to change any configuration
_format can be used to pick desired file format
All code reside inside controller (and some services related to particular format gen), so adding new stuff or changing existing require changes in small number of files.
I just installed FOSRestBundle I´m getting this error when I run cache:clear
[Symfony\Component\Config\Exception\FileLoaderLoadException]
Cannot import resource "/Users/gitek/www/hotel/src/Gitek/RegistroBundle/Resources/config/routing_incidencia.yml" from "/Users/gitek/www/hotel/app/config/routing.yml".
[RuntimeException]
The autoloader expected class "Gitek\RegistroBundle\Controller\IncidenciaController" to be defined in file "/Users/gitek/www/hotel/app/../src/Gitek/RegistroBundle/Controller/IncidenciaController.php". The file was found but the class was not in it, the class name or namespace probably has a typo.
This is my controller:
<?php
namespace Gitek\RegistroBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\View\View;
use Gitek\RegistroBundle\Entity\Registro;
use Gitek\HotelBundle\Entity\Incidencia;
class UsuarioController extends Controller
{
public function putIncidenciaAction($registro_id, $incidencia_id)
{
$em = $this->get('doctrine')->getEntityManager();
$registro = $em->getRepository('RegistroBundle:Registro')->find($registro_id);
$incidencia = $em->getRepository('HotelBundle:Incidencia')->find($incidencia_id);
$request = $this->getRequest();
$registro->setIncidencia($incidencia);
$em->persist($registro);
$em->flush();
$view = View::create();
$view->setData($registro);
return $view;
} // "put_incidencia" [PUT] /incidencia/{registro_id, incidencia_id}
}
This is my #app/config/routing.yml
incidencias:
resource: "#RegistroBundle/Resources/config/routing_incidencia.yml"
prefix: /
type: rest
This is my #src/Gitek/RegistroBundle/Resources/config/routing_incidencia.yml
incidencia:
type: rest
resource: Gitek\RegistroBundle\Controller\IncidenciaController
name_prefix: api_
Finally, this is my config for fos_rest on #app/config.yml:
fos_rest:
routing_loader:
default_format: null
view:
default_engine: twig
force_redirects:
html: true
formats:
json: true
xml: true
templating_formats:
html: true
view_response_listener: 'force'
failed_validation: HTTP_BAD_REQUEST
exception:
codes: ~
messages: ~
body_listener:
decoders:
json: fos_rest.decoder.json
xml: fos_rest.decoder.xml
format_listener:
default_priorities: [json, html, '*/*']
fallback_format: html
prefer_extension: true
service:
router: router
templating: templating
serializer: serializer
view_handler: fos_rest.view_handler.default
Any help or clue??
Your controller class should be named IncidenciaController instead of UsuarioController