Custom actions in your REST API
An updated article on this topic (with a different recommendation) is provided here, as part of my series of articles on RESTful API design.
While working on a REST API for Humanitarian ID, I came across a tricky (and therefore interesting) use case for a REST API: custom actions.
What are custom actions ?
Examples of custom actions are voting on a resource, subscribing to a service, starring or following a resource etc... basically any action which doesn't fit in the CRUD world. While CRUD operations are fairly easy to handle restfully, custom actions do not fit so well in the REST paradigm, so how can we handle them "RESTfully".
REST Principles
REST principles actually state that resources should be named with nouns, while an HTTP Verb (such as GET, POST, PUT or DELETE) should be used to describe an action on these resources. For example:
-
GET /users
: read all users -
GET /users/12
: read user with ID 12 -
POST /users
: create a new user -
PUT /users/12
: update user with ID 12 -
DELETE /users/12
: delete user with ID 12
Let's say I want to add an action which subscribes a user to a list (another type of resource in my API). What are the options ?
Action in the URL
The first idea I had was to add an action verb in the URL, to have something like:
PUT /users/12/subscribe
This is, however, NOT Restful. Why ? Because there is an action, a verb, in the URL, and REST principles state that the action should only be in the HTTP verb, while URLs should be used to identify resources only.
While you can create a perfectly working API with an action in the URL, it will not, in the strict sense of the term, be restful.
Thinking RESTFUL: subscriptions
Instead of thinking in terms of actions, such as subscribing/unsubscribing a user to/from a list, RESTful tells us to think in terms of resources. When subscribing a user to a list, we are actually creating a subscription resource. The following 3 alternatives ARE RESTFUL, and the one you chose will actually depend on your underlying data model and where you want your subscriptions to be stored.
Option 1: subscriptions as a new resource type
This would be something like:
GET /subscriptions
POST /subscriptions
PUT /subscriptions/1
DELETE /subscriptions/1
Each subscription resource would hold a reference to a user and to a list.
Option 2: subscriptions belonging to a user
This would be something along the lines of:
GET /users/12/subscriptions
POST /users/12/subscriptions
PUT /users/12/subscriptions/1
DELETE /users/12/subscriptions/1
Subscriptions would be stored in the user object, and would contain a reference to a list.
Option 3: subscriptions belonging to a list
Here, we would have something like:
GET /lists/16/subscriptions
POST /lists/16/subscriptions
PUT /lists/16/subscriptions/1
DELETE /lists/16/subscriptions/1
Subscriptions would be stored in the list object, and would contain a reference to a user.
The choice between options 1, 2 and 3 will probably depend on where it is more convenient for your app to have the subscriptions stored. If you often need to fetch the list of subscriptions of a user, you are probably better off going for option 2: it depends on your requirements. That said, all of the options above are RESTful.
This series of articles about Restful API design is also available as an eBook on Amazon, if you need it in a handy format.
Comments
What if...
What if you wanted to create an action url for lets say.. power off virtual machine? /VirtualMachine/12345/PowerOff
And if you say to create a "virtual machine state" property on the virtual machine class or create new object, then does it then require MORE WORK to process the entire passed in objects and spot the changes, rather than getting a direct action, with a small specific order/command?
I suppose here you'll have a
I suppose here you'll have a clear trade-off: time spent on implementation vs non-RESTful action, which may lead to lower comprehensiveness of the API.
Add new comment