diff --git a/README.md b/README.md index 0a832ca39..3ff46a4c3 100644 --- a/README.md +++ b/README.md @@ -1,839 +1,35 @@ -RestBundle -========== +FOSRestBundle +============= -This bundle provides various tools to rapidly develop RESTful API's & applications with Symfony2 -This version is compatible with Symfony2 master version, aka 2.1 and later. Use the 2.0 branch -when using 2.0.x versions of Symfony2. +> Note: This branch is compatible with Symfony2 master (2.1.x). +> For Symfony2 2.0.x compatibility use the 2.0 branch. -It is currently under development so key pieces that are planned are still missing. -See here for more details on what is planned: -https://github.com/FriendsOfSymfony/FOSRestBundle/issues +This bundle provides various tools to rapidly develop RESTful API's & +applications with Symfony2. Features include: -For now the Bundle provides a view layer to enable output (including redirects) and -format agnostic Controllers (using the JMSSerializerBundle for serialization -of formats that do not use template). - -Furthermore a custom route loader can be used when following a method naming convention. -It will automatically provide routes for multiple actions by simply -configuring the name of a controller. - -It also has support for RESTful decoding of HTTP request body and Accept headers -as well as a custom Exception controller that assists in using appropriate HTTP -status codes. +- A View layer to enable output and format agnostic Controllers +- A custom route loader to generate url's following REST conventions +- RESTful decoding of HTTP request body and Accept headers +- Exception controller for sending appropriate HTTP status codes [![Build Status](https://secure.travis-ci.org/FriendsOfSymfony/FOSRestBundle.png?branch=master)](http://travis-ci.org/FriendsOfSymfony/FOSRestBundle) -Installation -============ - -### Add this bundle to your project - -**Using the vendors script** - -Add the following lines in your deps file: - - [FOSRestBundle] - git=git://github.com/FriendsOfSymfony/FOSRestBundle.git - target=bundles/FOS/RestBundle - -You will also need to install the -[JMSSerializerBundle](https://github.com/schmittjoh/JMSSerializerBundle). This bundle is used -for serialization. Please see the bundle's [documentation](https://github.com/schmittjoh/JMSSerializerBundle/blob/master/Resources/doc/index.rst) -for configuration instructions. Add these lines to your deps file: - - [JMSSerializerBundle] - git=git://github.com/schmittjoh/JMSSerializerBundle.git - target=bundles/JMS/SerializerBundle - -Run the vendors script: - -```bash -$ php bin/vendors install -``` - -**Using Git submodule** +Documentation +------------- -```bash -$ git submodule add git://github.com/FriendsOfSymfony/FOSRestBundle.git vendor/bundles/FOS/RestBundle -``` +The bulk of the documentation is stored in the `Resources/doc/index.md` +file in this bundle: -### Add the FOS namespace to your autoloader +[Read the Documentation](https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/doc/index.md) -```php -registerNamespaces(array( - 'FOS' => __DIR__.'/../vendor/bundles', - // your other namespaces -)); -``` - -### Add this bundle to your application's kernel - -```php -setStatusCode(200) - ->setData($data); - - ... - - return $this->get('fos_rest.view_handler')->handle($view); - } -} -``` - -In the above example, ``View::create`` is a simple, convenient method to allow -for a fluent interface. It is equivalent to instantiating a View by calling its -constructor. - -As the purpose is to create a format-agnostic controller, data assigned to the ``View`` -instance should ideally be an object graph, though any data type is acceptable. Note that when rendering -templating formats, the ``ViewHandler`` will wrap data types other than associative arrays in an -associative array with a single key (default ``'data'``), which will become the variable name of the -object in the respective template. - -There are also two specialized ``View`` classes for handling directs, one for redirecting -to an URL called ``RedirectView`` and one to redirect to a route called ``RouteRedirectView``. -Note that whether these classes actually cause a redirect or not is determined by the -``force_redirects`` configuration option, which is only enabled for ``html`` by default (see below). - -See the following example code for more details: -https://github.com/liip/LiipHelloBundle/blob/master/Controller/HelloController.php - -### Configuration - -The ``formats`` and ``templating_formats`` settings determine which formats are respectively supported by -the serializer and by the template layer. In other words any format listed in ``templating_formats`` -will require a template for rendering using the ``templating`` service, while any format -listed in ``formats`` will use JMSSerializerBundle for rendering. For both settings a value of -``false`` means that the given format is disabled. - -When using ``RouteRedirectView::create()`` the default behavior of forcing a redirect to the -route for html is enabled, but needs to be enabled for other formats if needed. - -Finally the HTTP response status code for failed validation defaults to ``400``. Note when -changing the default you can use name constants of ``FOS\RestBundle\Response\Codes`` class or -an integer status code. - -You can also set the default templating engine to something different than the default of ``twig``: - -```yaml -# app/config/config.yml -fos_rest: - view: - formats: - rss: true - xml: false - templating_formats: - html: true - force_redirects: - html: true - failed_validation: HTTP_BAD_REQUEST - default_engine: twig -``` - -See the following example configuration for more details: -https://github.com/lsmith77/symfony-standard/blob/techtalk/app/config/config.yml - -### Custom handler - -While many things should be possible via the JMSSerializerBundle in some cases it might -not be enough. For example you might need some custom logic to be executed in the -``ViewHandler``. For these cases one might want to register a custom handler for a -specific format. The custom handler can either be registered by defining a custom service, -via a compiler pass or it can even be registered from inside the controller action. - -The callable will receive 3 parameters: - - * the instance of the ``ViewHandler`` - * the instance of the ``View`` - * the instance of the ``Request`` - -Note there are several public methods on the ``ViewHandler`` which can be helpful: - - * ``isFormatTemplating()`` - * ``createResponse()`` - * ``createRedirectResponse()`` - * ``renderTemplate()`` - -There is an example inside LiipHelloBundle to show how to register a custom handler: -https://github.com/liip/LiipHelloBundle/blob/master/View/RSSViewHandler.php -https://github.com/liip/LiipHelloBundle/blob/master/Resources/config/config.yml - -There is another example in ``Resources\docs\examples``: -https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/docs/examples/RssHandler.php - -Here is an example using a closure registered inside a Controller action: - -```php -get('fos_rest.view_handler'); - if (!$handler->isFormatTemplating($view->getFormat())) { - $templatingHandler = function($handler, $view, $request) { - // if a template is set, render it using the 'params' and place the content into the data - if ($view->getTemplate()) { - $data = $view->getData(); - if (empty($data['params'])) { - $params = array(); - } else { - $params = $data['params']; - unset($data['params']); - } - $view->setData($params); - $data['html'] = $handler->renderTemplate($view, 'html'); - - $view->setData($data); - } - return $handler->createResponse($view, $request, $format); - } - $handler->registerHandler($view->getFormat(), $templatingHandler); - } - return $handler->handle($view); - } -} -``` - -Listener support ----------------- - -All listeners except the ``mime_type`` one are enabled by default. -You can disable one or more of these listeners. -For example, below you can see how to disable all listeners: - -```yaml -# app/config/config.yml -fos_rest: - body_listener: false - format_listener: false - view: - view_response_listener: false -``` - -### View Response listener - -The view response listener makes it possible to simply return a ``View`` instance from action -controllers. The final output will then automatically be processed via the listener by the -``fos_rest.view_handler`` service. - -This requires adding the SensioFrameworkExtraBundle to your vendors: - -http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html - -Now inside a controller its possible to simply return a ``View`` instance. - -```php -setData($data); - return $view; - } -} -``` - -As this feature is heavily based on the SensioFrameworkBundle, the example can further be -simplified by using the various annotations supported by that bundle. There is also one -additional annotation called ``@View()`` which extends from the ``@Template()`` annotation. - -The ``@View()`` and ``@Template()`` annotations behave essentially the same with a minor -difference. When ``view_response_listener`` is set to ``true`` instead of the default ``force`` -and ``@View()`` is not used, then rendering will be delegated to SensioFrameworkBundle. - -Note that it is necessary to disable view annotations in SensioFrameworkBundle so that -FOSRestBundle can take over the handling. - -```yaml -# app/config/config.yml -fos_rest: - view: - view_response_listener: force - -sensio_framework_extra: - view: { annotations: false } - router: { annotations: true } -``` - -```php -validate($slug)) { - throw new HttpException(400, "New comment is not valid."); - } - } -} -``` - -See the following example configuration for more details: -https://github.com/lsmith77/symfony-standard/blob/techtalk/app/config/config.yml - -Routing -======= - -The RestBundle provides custom route loaders to help in defining REST friendly routes -as well as reducing the manual work of configuring routes and the given requirements -(like making sure that only GET may be used in certain routes etc.). - -You may specify a ``default_format`` that the routing loader will use for the ``_format`` -parameter if none is specified. - -```yaml -# app/config/config.yml -fos_rest: - routing_loader: - default_format: json -``` - -Many of the features explained below are used in the following example code: -https://github.com/liip/LiipHelloBundle/blob/master/Controller/RestController.php - -Single RESTful controller routes --------------------------------- - -```yaml -# app/config/routing.yml -users: - type: rest - resource: Acme\HelloBundle\Controller\UsersController -``` - -```xml -# app/config/routing.xml - - - - - - -``` - -This will tell Symfony2 to automatically generate proper REST routes from your ``UsersController`` action names. -Notice ``type: rest`` option. It's required so that the RestBundle can find which routes are supported. - -## Define resource actions - -```php - - - - - - - -``` - -Notice ``parent: users`` option in the second case. This option specifies that the comments resource -is child of the users resource. In this case, your ``UsersController`` MUST always have a single -resource ``get...`` action: - -```php - This bundle depends on the [JMSSerializerBundle](https://github.com/schmittjoh/JMSSerializerBundle). Please follow the instructions of the bundle to set it up. + + +Ultimately, the FOSRestBundle files should be downloaded to the +`vendor/bundles/FOS/RestBundle` directory. + +This can be done in several ways, depending on your preference. The first +method is the standard Symfony2 method. + +**Using the vendors script** + +Add the following lines in your `deps` file: + +``` +[FOSRestBundle] + git=git://github.com/FriendsOfSymfony/FOSRestBundle.git + target=bundles/FOS/RestBundle +``` + +Now, run the vendors script to download the bundle: + +``` bash +$ php bin/vendors install +``` + +**Using submodules** + +If you prefer instead to use git submodules, then run the following: + +``` bash +$ git submodule add git://github.com/FriendsOfSymfony/FOSRestBundle.git vendor/bundles/FOS/RestBundle +$ git submodule update --init +``` + +### B) Configure the Autoloader + +Add the `FOS` namespace to your autoloader: + +``` php +registerNamespaces(array( + // ... + 'FOS' => __DIR__.'/../vendor/bundles', +)); +``` + +### C) Enable the bundle + +Finally, enable the bundle in the kernel: + +``` php +setStatusCode(200) + ->setData($data); + + ... + + return $this->get('fos_rest.view_handler')->handle($view); + } +} +``` + +In the above example, ``View::create`` is a simple, convenient method to allow +for a fluent interface. It is equivalent to instantiating a View by calling its +constructor. + +As the purpose is to create a format-agnostic controller, data assigned to the +``View`` instance should ideally be an object graph, though any data type is +acceptable. Note that when rendering templating formats, the ``ViewHandler`` +will wrap data types other than associative arrays in an associative array with +a single key (default ``'data'``), which will become the variable name of the +object in the respective template. + +There are also two specialized ``View`` classes for handling directs, one for +redirecting to an URL called ``RedirectView`` and one to redirect to a route +called ``RouteRedirectView``. Note that whether these classes actually cause a +redirect or not is determined by the ``force_redirects`` configuration option, +which is only enabled for ``html`` by default (see below). + +See the following example code for more details: +https://github.com/liip/LiipHelloBundle/blob/master/Controller/HelloController.php + +### Configuration + +The ``formats`` and ``templating_formats`` settings determine which formats are +respectively supported by the serializer and by the template layer. In other +words any format listed in ``templating_formats`` will require a template for +rendering using the ``templating`` service, while any format listed in +``formats`` will use JMSSerializerBundle for rendering. For both settings a +value of ``false`` means that the given format is disabled. + +When using ``RouteRedirectView::create()`` the default behavior of forcing a +redirect to the route for html is enabled, but needs to be enabled for other +formats if needed. + +Finally the HTTP response status code for failed validation defaults to +``400``. Note when changing the default you can use name constants of +``FOS\RestBundle\Response\Codes`` class or an integer status code. + +You can also set the default templating engine to something different than the +default of ``twig``: + +```yaml +# app/config/config.yml +fos_rest: + view: + formats: + rss: true + xml: false + templating_formats: + html: true + force_redirects: + html: true + failed_validation: HTTP_BAD_REQUEST + default_engine: twig +``` + +See the following example configuration for more details: +https://github.com/lsmith77/symfony-standard/blob/techtalk/app/config/config.yml + +### Custom handler + +While many things should be possible via the JMSSerializerBundle in some cases +it might not be enough. For example you might need some custom logic to be +executed in the ``ViewHandler``. For these cases one might want to register a +custom handler for a specific format. The custom handler can either be +registered by defining a custom service, via a compiler pass or it can even be +registered from inside the controller action. + +The callable will receive 3 parameters: + + * the instance of the ``ViewHandler`` + * the instance of the ``View`` + * the instance of the ``Request`` + +Note there are several public methods on the ``ViewHandler`` which can be helpful: + + * ``isFormatTemplating()`` + * ``createResponse()`` + * ``createRedirectResponse()`` + * ``renderTemplate()`` + +There is an example inside LiipHelloBundle to show how to register a custom handler: +https://github.com/liip/LiipHelloBundle/blob/master/View/RSSViewHandler.php +https://github.com/liip/LiipHelloBundle/blob/master/Resources/config/config.yml + +There is another example in ``Resources\docs\examples``: +https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/docs/examples/RssHandler.php + +Here is an example using a closure registered inside a Controller action: + +```php +get('fos_rest.view_handler'); + if (!$handler->isFormatTemplating($view->getFormat())) { + $templatingHandler = function($handler, $view, $request) { + // if a template is set, render it using the 'params' and place the content into the data + if ($view->getTemplate()) { + $data = $view->getData(); + if (empty($data['params'])) { + $params = array(); + } else { + $params = $data['params']; + unset($data['params']); + } + $view->setData($params); + $data['html'] = $handler->renderTemplate($view, 'html'); + + $view->setData($data); + } + return $handler->createResponse($view, $request, $format); + } + $handler->registerHandler($view->getFormat(), $templatingHandler); + } + return $handler->handle($view); + } +} +``` + +## That was it! +[Return to the index](index.md) or continue reading about [Listener support](3-listener-support.md). diff --git a/Resources/doc/3-listener-support.md b/Resources/doc/3-listener-support.md new file mode 100644 index 000000000..6c8c6a9eb --- /dev/null +++ b/Resources/doc/3-listener-support.md @@ -0,0 +1,201 @@ +Step 3: Listener support +======================== +All listeners except the ``mime_type`` one are enabled by default. You can +disable one or more of these listeners. For example, below you can see how to +disable all listeners: + +```yaml +# app/config/config.yml +fos_rest: + body_listener: false + format_listener: false + view: + view_response_listener: false +``` + +### View Response listener + +The view response listener makes it possible to simply return a ``View`` +instance from action controllers. The final output will then automatically be +processed via the listener by the ``fos_rest.view_handler`` service. + +This requires adding the SensioFrameworkExtraBundle to your vendors: + +http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html + +Now inside a controller its possible to simply return a ``View`` instance. + +```php +setData($data); + return $view; + } +} +``` + +As this feature is heavily based on the SensioFrameworkBundle, the example can +further be simplified by using the various annotations supported by that +bundle. There is also one additional annotation called ``@View()`` which +extends from the ``@Template()`` annotation. + +The ``@View()`` and ``@Template()`` annotations behave essentially the same +with a minor difference. When ``view_response_listener`` is set to ``true`` +instead of the default ``force`` and ``@View()`` is not used, then rendering +will be delegated to SensioFrameworkBundle. + +Note that it is necessary to disable view annotations in SensioFrameworkBundle +so that FOSRestBundle can take over the handling. + +```yaml +# app/config/config.yml +fos_rest: + view: + view_response_listener: force + +sensio_framework_extra: + view: { annotations: false } + router: { annotations: true } +``` + +```php +validate($slug)) { + throw new HttpException(400, "New comment is not valid."); + } + } +} +``` + +See the following example configuration for more details: +https://github.com/lsmith77/symfony-standard/blob/techtalk/app/config/config.yml + +## That was it! +[Return to the index](index.md) or continue reading about [Automatic route generation: single RESTful controller](5-automatic-route-generation_single-restful-controller.md). diff --git a/Resources/doc/5-automatic-route-generation_single-restful-controller.md b/Resources/doc/5-automatic-route-generation_single-restful-controller.md new file mode 100644 index 000000000..7c64722de --- /dev/null +++ b/Resources/doc/5-automatic-route-generation_single-restful-controller.md @@ -0,0 +1,156 @@ +Routing +======= + +The RestBundle provides custom route loaders to help in defining REST friendly +routes as well as reducing the manual work of configuring routes and the given +requirements (like making sure that only GET may be used in certain routes +etc.). + +You may specify a ``default_format`` that the routing loader will use for the +``_format`` parameter if none is specified. + +```yaml +# app/config/config.yml +fos_rest: + routing_loader: + default_format: json +``` + +Many of the features explained below are used in the following example code: +https://github.com/liip/LiipHelloBundle/blob/master/Controller/RestController.php + +Single RESTful controller routes +================================ + +```yaml +# app/config/routing.yml +users: + type: rest + resource: Acme\HelloBundle\Controller\UsersController +``` + +This will tell Symfony2 to automatically generate proper REST routes from your ``UsersController`` action names. +Notice ``type: rest`` option. It's required so that the RestBundle can find which routes are supported. + +## Define resource actions + +```php + + + + + + + +``` + +Notice ``parent: users`` option in the second case. This option specifies that the comments resource +is child of the users resource. In this case, your ``UsersController`` MUST always have a single +resource ``get...`` action: + +```php +