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
================================

In this section we are looking at controllers for resources without sub-resources.
Handling of sub-resources requires some additional considerations which
are explained in the next section.

```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.

Notice the ``name_prefix: my_bundle_`` option. It's useful to prefix the generated controller routes to organize
your several resources paths. Take care that you can use ``name_prefix`` on an import only when the file is imported
itself with the type ``rest``. The parent option is used in sub-resources as we will see in the next section for
multiple RESTful controller routes.

## Define resource actions

```php
<?php
class UsersController
{
    public function optionsUsersAction()
    {} // "options_users" [OPTIONS] /users

    public function getUsersAction()
    {} // "get_users"     [GET] /users

    public function newUsersAction()
    {} // "new_users"     [GET] /users/new

    public function postUsersAction()
    {} // "post_users"    [POST] /users

    public function patchUsersAction()
    {} // "patch_users"   [PATCH] /users

    public function getUserAction($slug)
    {} // "get_user"      [GET] /users/{slug}

    public function editUserAction($slug)
    {} // "edit_user"     [GET] /users/{slug}/edit

    public function putUserAction($slug)
    {} // "put_user"      [PUT] /users/{slug}

    public function patchUserAction($slug)
    {} // "patch_user"    [PATCH] /users/{slug}

    public function lockUserAction($slug)
    {} // "lock_user"     [PATCH] /users/{slug}/lock

    public function banUserAction($slug)
    {} // "ban_user"      [PATCH] /users/{slug}/ban

    public function removeUserAction($slug)
    {} // "remove_user"   [GET] /users/{slug}/remove

    public function deleteUserAction($slug)
    {} // "delete_user"   [DELETE] /users/{slug}

    public function getUserCommentsAction($slug)
    {} // "get_user_comments"    [GET] /users/{slug}/comments

    public function newUserCommentsAction($slug)
    {} // "new_user_comments"    [GET] /users/{slug}/comments/new

    public function postUserCommentsAction($slug)
    {} // "post_user_comments"   [POST] /users/{slug}/comments

    public function getUserCommentAction($slug, $id)
    {} // "get_user_comment"     [GET] /users/{slug}/comments/{id}

    public function editUserCommentAction($slug, $id)
    {} // "edit_user_comment"    [GET] /users/{slug}/comments/{id}/edit

    public function putUserCommentAction($slug, $id)
    {} // "put_user_comment"     [PUT] /users/{slug}/comments/{id}

    public function postUserCommentVoteAction($slug, $id)
    {} // "post_user_comment_vote" [POST] /users/{slug}/comments/{id}/vote

    public function removeUserCommentAction($slug, $id)
    {} // "remove_user_comment"  [GET] /users/{slug}/comments/{id}/remove

    public function deleteUserCommentAction($slug, $id)
    {} // "delete_user_comment"  [DELETE] /users/{slug}/comments/{id}

    public function linkUserAction($slug)
    {} // "link_user_friend"     [LINK] /users/{slug}

    public function unlinkUserAction($slug)
    {} // "link_user_friend"     [UNLINK] /users/{slug}
}
```

That's all. All your resource (``UsersController``) actions will get mapped to the proper routes
as shown in the comments in the above example. Here are a few things to note:

#### Implicit resource name definition

Its possible to omit the ``User`` part of the method names when the Controller implements the
``ClassResourceInterface``. In this case FOSRestBundle can determine the resource based on the
Controller name. However for this to work its important to use singular names in the Controller.
However by omitting the resource name from the methods ``getUserAction`` and ``getUsersAction``
there would be an overlap of method names there is a special convention to call the methods
``getAction`` and ``cgetAction``, where the ``c`` standard for collection. So the following
would work as well.

```
<?php

use FOS\RestBundle\Routing\ClassResourceInterface;

class UserController implements ClassResourceInterface
{
    ..

    public function cgetAction()
    {} // "get_users"     [GET] /users

    public function newAction()
    {} // "new_users"     [GET] /users/new

    public function getAction($slug)
    {} // "get_user"      [GET] /users/{slug}

    ..
    public function getCommentsAction($slug)
    {} // "get_user_comments"    [GET] /users/{slug}/comments

    ..
}
```

Finally its possible to override the resource name derived from the Controller name via the
``@RouteResource`` annotation:


```
<?php

use FOS\RestBundle\Controller\Annotations\RouteResource;

/**
 * @RouteResource("User")
 */
class FooController
{
    ..

    public function cgetAction()
    {} // "get_users"     [GET] /users

    public function newAction()
    {} // "new_users"     [GET] /users/new

    public function getAction($slug)
    {} // "get_user"      [GET] /users/{slug}

    ..
    public function getCommentsAction($slug)
    {} // "get_user_comments"    [GET] /users/{slug}/comments

    ..
}
```

### REST Actions

There are 8 actions that have special meaning in regards to REST and have the following behavior:

* **get** - this action accepts *GET* requests to the url */resources* and returns all resources for this type. Shown as
``UsersController::getUsersAction()`` above. This action also accepts *GET* requests to the url */resources/{id}* and
returns a single resource for this type. Shown as ``UsersController::getUserAction()`` above.
* **post** - this action accepts *POST* requests to the url */resources* and creates a new resource of this type. Shown
as ``UsersController::postUsersAction()`` above.
* **put** - this action accepts *PUT* requests to the url */resources/{id}* and updates a single resource for this type.
Shown as ``UsersController::putUserAction()`` above.
* **delete** - this action accepts *DELETE* requests to the url */resources/{id}* and deletes a single resource for this
type. Shown as ``UsersController::deleteUserAction()`` above.
* **patch** - this action accepts *PATCH* requests to the url */resources* and is supposed to partially modify collection
of resources (e.g. apply batch modifications to subset of resources). Shown as ``UsersController::patchUsersAction()`` above.
This action also accepts *PATCH* requests to the url */resources/{id}* and is supposed to partially modify the resource.
Shown as ``UsersController::patchUserAction()`` above.
* **options** - this action accepts *OPTIONS* requests to the url */resources* and is supposed to return a list of REST
resources that the user has access to.  Shown as ``UsersController::optionsUsersAction()`` above.
* **link** - this action accepts *LINK* requests to the url */resources/{id}* and is supposed to return nothing but a
status code indicating that the specified resources were linked. It is used to declare a resource as related to an other one.
When calling a LINK url you must provide in your header at least one link header formatted as follow :
``<http://example.com/resources/{id}\>; rel="kind_of_relation"``
* **unlink** - this action accepts *UNLINK* requests to the url */resources/{id}* and is supposed to return nothing but
a status code indicating that the specified resources were unlinked. It is used to declare that some resources are not
related anymore. When calling a UNLINK url you must provide in your header at least one link header formatted as follow :
``<http://example.com/resources/{id}\>; rel="kind_of_relation"``

Important note about **link** and **unlink**: The implementation of the request listener extracting the resources as entities is not provided
by this bundle. A good implementation can be found here : http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/
It also contains some examples on how to use it. **link** and **unlink** were obsoleted by RFC 2616, RFC 5988 aims to define
it in a more clear way. Using these methods is not risky, but remains unclear (cf. issues 323 and 325).

### Conventional Actions

HATEOAS, or Hypermedia as the Engine of Application State, is an aspect of REST which allows clients to interact with the
REST service with hypertext - most commonly through an HTML page. There are 3 Conventional Action routings that are
supported by this bundle:

* **new** - A hypermedia representation that acts as the engine to *POST*. Typically this is a form that allows the client
to *POST* a new resource. Shown as ``UsersController::newUsersAction()`` above.
* **edit** - A hypermedia representation that acts as the engine to *PUT*. Typically this is a form that allows the client
to *PUT*, or update, an existing resource. Shown as ``UsersController::editUserAction()`` above.
* **remove** - A hypermedia representation that acts as the engine to *DELETE*. Typically this is a form that allows the
client to *DELETE* an existing resource. Commonly a confirmation form. Shown as ``UsersController::removeUserAction()`` above.

### Custom PATCH Actions

All actions that do not match the ones listed in the sections above will register as a *PATCH* action. In the controller
shown above, these actions are ``UsersController::lockUserAction()``, ``UsersController::banUserAction()`` and
``UsersController::voteUserCommentAction()``. You could just as easily create a method called
``UsersController::promoteUserAction()`` which would take a *PATCH* request to the url */users/{slug}/promote*.
This allows for easy updating of aspects of a resource, without having to deal with the resource as a whole at
the standard *PATCH* or *PUT* endpoint.

### Sub-Resource Actions

Of course it's possible and common to have sub or child resources. They are easily defined within the same controller by
following the naming convention ``ResourceController::actionResourceSubResource()`` - as seen in the example above with
``UsersController::getUserCommentsAction()``. This is a good strategy to follow when the child resource needs the parent
resource's ID in order to look up itself.

### Optional {_format} in route

By default, routes are generated with {_format} string. If you want to get clean urls (``/orders`` instead ``/orders.{_format}``)
then all you have to do is add some configuration:

```yml
# app/config/config.yml
fos_rest:
    routing_loader:
        include_format:       false
```

The {_format} route requirement is automatically positioned using the available listeners. So by default, the  requirement will
be {json|xml|html}. If you want to limit or add a custom format, you can do so by overriding it with the ``@Route`` annotation
(or another one extending it, like ``@Get``, ``@Post``...):

```php
<?php

use FOS\RestBundle\Controller\Annotations\Route;

    ..

    /**
     * @Route(requirements={"_format"="json|xml"})
     */
    public function getAction($slug)
    {}

    ..
}
```

## That was it!
[Return to the index](index.md) or continue reading about [Automatic route generation: multiple RESTful controllers](6-automatic-route-generation_multiple-restful-controllers.md).
