RESTful routing
REST and RESTful
According to Wikipedia, representational state transfer (REST) is a style of software architecture for distributed hypermedia systems such as the World Wide Web.
There are a few principles associated with the REST concept. Basically the following two are the most important in REST:
- Everything is an identifiable resource.
- Representational state of a resource is accessed through a set of standard methods in HTTP protocol.
Conforming to the REST constraints is often referred to as being "RESTful".
Resource and routes
Once a resource is declared in routes.properties file, Scooter creates up to seven restful style routes of default actions (index, show, add, create, edit, update, and delete).
For example, if we declare a resource named pets,
resources.list=pets
Scooter automatically creates seven routes for the resource pets:
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /pets | pets | index | display a list of all pets |
GET | /pets/add | pets | add | return an HTML form for creating a new pet |
POST | /pets | pets | create | create a new pet |
GET | /pets/$id | pets | show | display a specific pet |
GET | /pets/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /pets/$id | pets | update | update a specific pet |
DELETE | /pets/$id | pets | delete | delete a specific pet |
As you can see from the above table, CRUD operations on a resource are done by using standard HTTP methods. In this way, every resource exposes a standard interface that is understandable by other applications on the Web.
Singular resources
By default, resources are in plural form. However, there are situations for singular resource. In this case, you simply declare it by using word resource in its singular form:
resource.list=admin
For a singular resource, Scooter creates six routes:
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /admin/add | admin | add | return an HTML form for creating the new admin |
POST | /admin | admin | create | create the new admin |
GET | /admin | admin | show | display the admin |
GET | /admin/edit | admin | edit | return an HTML form for editing the admin |
PUT | /admin | admin | update | update the admin |
DELETE | /admin | admin | delete | delete the admin |
Resource control options
There are situations that you may not all seven routes for a resource, or you may want to hide the actual resource name from the url. You can do this kind of fine control by using control options related to a resource.
Scooter supports the following control options for a resource:
- controller
- controller_class
- singular
- namespace
- path_prefix
- path_alias
- action_alias
- only
- except
- member
- collection
- add
- requirements
- parents
- strict
In the rest of this section, we will give a detail example for each option. You can play with the examples simply by pasting it to your routes.properties file and see the effects of the options by clicking on the routes on top of your admin screen.
controllerBy default, Scooter uses resource name as controller name. For example, for resource pets, the default controller class would be PetsController. However, if you want to use AnimalsController as the controller class for this resource, you may simply do the following:
resources.name.pets=\ controller:animals
controller is used by Scooter to derive the controller class name. You may use the controller_class option to directly indicate the class name too.
controller_classBy default, controllers are located in the controllers directory. For example, for resource pets, the default controller class would be petclinic.controllers.PetsController. If you want to use com.example.AnimalsController class, for this resource, you may simply do the following:
resources.name.pets=\ controller_class:com.example.AnimalsControllersingular
By default, resource name is plural and model name is singular. Scooter derives model name from a resource name. For example, if a resource is people, Scooter can derive its model name as person. However, in situations where Scooter fails to derive a good singular name from the resource name, you may use singular option to tell Scooter what the correct singular form of the resource name.
resources.name.countries=\ singular:statenamespace
By default, controllers are located in the controllers directory. For example, for resource pets, the default controller class would be PetsController.class under that folder. However, in case you like to group all your controller classes together and put them under a subdirectory named manager, you use the namespace option as follows:
resources.name.pets=\ namespace:managerpath_prefix
The path_prefix option lets you add additional parameters in url.
For example, if we specify a path prefix as path_prefix,
resources.name.pets=\ path_prefix:/stores/$store_id
the seven routes created by Scooter will be like the following:
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /stores/$store_id/pets | pets | index | display a list of all pets |
GET | /stores/$store_id/pets/add | pets | add | return an HTML form for creating a new pet |
POST | /stores/$store_id/pets | pets | create | create a new pet |
GET | /stores/$store_id/pets/$id | pets | show | display a specific pet |
GET | /stores/$store_id/pets/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /stores/$store_id/pets/$id | pets | update | update a specific pet |
DELETE | /stores/$store_id/pets/$id | pets | delete | delete a specific pet |
In each route, a store_id parameter appears in the url.
path_aliasBy default, Scooter uses resource name to create url for a route. If you want to hide the actual resource name from the url, you may use the path_alias option:
resources.name.pets=\ path_alias:animals
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /animals | pets | index | display a list of all pets |
GET | /animals/add | pets | add | return an HTML form for creating a new pet |
POST | /animals | pets | create | create a new pet |
GET | /animals/$id | pets | show | display a specific pet |
GET | /animals/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /animals/$id | pets | update | update a specific pet |
DELETE | /animals/$id | pets | delete | delete a specific pet |
The controller name and action name are not changed. Only the url is changed.
action_aliasThe URLs for the seven routes created for a resource expose action names like add and edit. You can hide the actual action names by using the action_alias option:
resources.name.pets=\ action_alias:{add=>make, edit=>change}
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /pets | pets | index | display a list of all pets |
GET | /pets/make | pets | add | return an HTML form for creating a new pet |
POST | /pets | pets | create | create a new pet |
GET | /pets/$id | pets | show | display a specific pet |
GET | /pets/$id/change | pets | edit | return an HTML form for editing a pet |
PUT | /pets/$id | pets | update | update a specific pet |
DELETE | /pets/$id | pets | delete | delete a specific pet |
The controller name and action name are not changed. Only the url is changed.
onlyBy default, seven routes are creates for each resource. You may limit the routes created by using the only option:
resources.name.pets=\ only:[index | show]
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /pets | pets | index | display a list of all pets |
GET | /pets/$id | pets | show | display a specific pet |
Now only readonly actions are allowed for the resource pets.
exceptexcept is similar as only. It allows you to exclude some routes. For example,
resources.name.pets=\ except:[update | delete];
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /pets | pets | index | display a list of all pets |
GET | /pets/add | pets | add | return an HTML form for creating a new pet |
POST | /pets | pets | create | create a new pet |
GET | /pets/$id | pets | show | display a specific pet |
GET | /pets/$id/edit | pets | edit | return an HTML form for editing a pet |
Now no one is allowed to update or delete a pet.
memberBy default, Scooter creates seven routes for a resource. If you want more routes, you use member option for adding routes that apply to a single instance of the resource.
For example, we can add a prepare route and a mypet route. The former is accessed by HTTP methods GET and POST, while the latter GET only.
resources.name.pets=\ member:{prepare=>[get | post], visit=>get}
The following two routes are added to the standard seven routes of pets:
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET|POST | /pets/$id/prepare | pets | prepare | prepare a pet |
GET | /pets/$id/visit | pets | visit | visit a pet |
GET | /pets | pets | index | display a list of all pets |
GET | /pets/add | pets | add | return an HTML form for creating a new pet |
POST | /pets | pets | create | create a new pet |
GET | /pets/$id | pets | show | display a specific pet |
GET | /pets/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /pets/$id | pets | update | update a specific pet |
DELETE | /pets/$id | pets | delete | delete a specific pet |
Now there are totally nine routes for the resource pets.
collectioncollection option is similar as the member option except that it adds routes that apply to a collection of instances of a resource.
resources.name.pets=\ collection:{search=>[get | post], paged_list=>get}
The following two routes are added to the standard seven routes of pets:
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /pets/paged_list | pets | paged_list | return a paged list of pets |
GET|POST | /pets/search | pets | search | search pets |
Now there are totally nine routes for the resource pets.
addadd option is similar as the member option except that it applies to creating a new resource.
For example, the following declaration adds an additional route to the seven standard routes.
resources.name.pets=\ add:{upload=>post}
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
POST | /pets/upload | pets | upload | upload a pet |
Now there are totally eight routes for the resource pets.
requirementsYou use the requirements option to restrict format of a parameter.
In the following example, we enforce that all $id parameters must consist of digits.
resources.name.pets=\ requirements : { id => /\\d+/ }parents
The parent option allows you to create nested routes.
For example, the following declaration would add 14 more routes to the seven standard routes for resource pets.
resources.name.pets=\ parents:[users | accounts]
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /users/$user_id/pets | pets | index | display a list of all pets |
GET | /users/$user_id/pets/add | pets | add | return an HTML form for creating a new pet |
POST | /users/$user_id/pets | pets | create | create a new pet |
GET | /users/$user_id/pets/$id | pets | show | display a specific pet |
GET | /users/$user_id/pets/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /users/$user_id/pets/$id | pets | update | update a specific pet |
DELETE | /users/$user_id/pets/$id | pets | delete | delete a specific pet |
GET | /accounts/$account_id/pets | pets | index | display a list of all pets |
GET | /accounts/$account_id/pets/add | pets | add | return an HTML form for creating a new pet |
POST | /accounts/$account_id/pets | pets | create | create a new pet |
GET | /accounts/$account_id/pets/$id | pets | show | display a specific pet |
GET | /accounts/$account_id/pets/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /accounts/$account_id/pets/$id | pets | update | update a specific pet |
DELETE | /accounts/$account_id/pets/$id | pets | delete | delete a specific pet |
GET | /pets | pets | index | display a list of all pets |
GET | /pets/add | pets | add | return an HTML form for creating a new pet |
POST | /pets | pets | create | create a new pet |
GET | /pets/$id | pets | show | display a specific pet |
GET | /pets/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /pets/$id | pets | update | update a specific pet |
DELETE | /pets/$id | pets | delete | delete a specific pet |
Now there are totally 21 routes for the resource pets.
strictThe parent option still allows direct access to a resource through urls like /pets. If you want to enforce that a resource is a pure nested resource in that it can only be accessed through its parent, you can use the strict option.
For example, the following declaration would change the urls of the seven standard routes for resource pets.
resources.name.pets=\ parents:strict users
HTTP verb | URL | controller | action | used for |
---|---|---|---|---|
GET | /users/$user_id/pets | pets | index | display a list of all pets |
GET | /users/$user_id/pets/add | pets | add | return an HTML form for creating a new pet |
POST | /users/$user_id/pets | pets | create | create a new pet |
GET | /users/$user_id/pets/$id | pets | show | display a specific pet |
GET | /users/$user_id/pets/$id/edit | pets | edit | return an HTML form for editing a pet |
PUT | /users/$user_id/pets/$id | pets | update | update a specific pet |
DELETE | /users/$user_id/pets/$id | pets | delete | delete a specific pet |
Now a user_id is required to access pets.
auto.rest property
auto.rest property in the routes.properties file indicates whether to automatically generate restful routes when a resources is not defined in the file.
The default value is false. 'true' is not recommended in production environment.
If you set this value to true, and access url /pets, then Scooter will treat pets as a resource and automatically create seven routes for it.
auto.rest=true