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:

  1. Everything is an identifiable resource.
  2. 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 verbURLcontrolleractionused 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 verbURLcontrolleractionused 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:

  1. controller
  2. controller_class
  3. singular
  4. namespace
  5. path_prefix
  6. path_alias
  7. action_alias
  8. only
  9. except
  10. member
  11. collection
  12. add
  13. requirements
  14. parents
  15. 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.

controller

By 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_class

By 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.AnimalsController
singular

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:state
namespace

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:manager
path_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 verbURLcontrolleractionused 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_alias

By 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 verbURLcontrolleractionused 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_alias

The 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 verbURLcontrolleractionused 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.

only

By 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 verbURLcontrolleractionused 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.

except

except is similar as only. It allows you to exclude some routes. For example,

resources.name.pets=\
        except:[update | delete];
HTTP verbURLcontrolleractionused 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.

member

By 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 verbURLcontrolleractionused 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.

collection

collection 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 verbURLcontrolleractionused 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.

add

add 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 verbURLcontrolleractionused for
POST /pets/upload pets upload upload a pet

Now there are totally eight routes for the resource pets.

requirements

You 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 verbURLcontrolleractionused 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.

strict

The 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 verbURLcontrolleractionused 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