Reputation: 1770
Before I decided to ask this question I have searched quite a long for the answer but I haven't found any satisfactory. (e.g. Examples of the best SOAP/REST/RPC web APIs? And why do you like them? And what's wrong with them?)
And the problem is actually quite simple. I have an object/resource named Account. My REST API supports all CRUDs with GET, POST, PUT and DELETE already with proper error handling, status codes etc.
Additionally however I want to expose an API ("command") to activate and deactivate selected Account resource. Even if the "isActive" is a property of the Account I don't want to use just the Update from my CRUD of the whole Account.
I know it is easy to violate REST principles and make RPC style design with such design like this:
PUT /api/account/:accountId/activate
PUT /api/account/:accountId/deactivate
So what is the best solution for this use case?
My current idea is to use PUT and DELETE verbs like this (to treat it as a sub-resource) as proposed here http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful:
PUT /api/account/:accountId/isActive // for activate
DELETE /api/account/:accountId/isActive // for deactivate
What are your solutions?
Upvotes: 35
Views: 20815
Reputation: 1615
The POST method would create the resource 'account'. Active can be seen as one of the properties of the resource 'account'. Hence it should be a PUT request.
I would say even deactivate must be a PUT request as the account resource will still exist.
To activate an account you can set a property on the resource. That is:
/api/account/{accountId}?activate=true
To deactivate:
/api/account/{accountId}?activate=false
A GET request on the account would return a JSON with the activate value in it.
A DELETE request should completely delete the account resource.
Upvotes: 4
Reputation: 118
PATCH is the most appropriate method in this case. Please find more at RESTful URL for "Activate"
Upvotes: 5
Reputation: 3280
First off, PUT
is appropriate compared to POST
, because you are creating a resource to an already-known location. And, I think, there's no dilemma about DELETE
. So at first glance, your current approach seems to beat the alternatives.
I used to think the same way, until I implemented my own REST api, in which I wanted the admin to be able to set an account in a deactivated - yet not deleted, just "banned" - state. When I gave it a little more thought, I decided to do it vice versa.
Let me explain. I like to see the activation
resource as "the option to activate the account". So if a url like /account/foo/activation
exists, it could only mean that the account is not activated and the user has the right to activate it. If it doesn't exist, the account is either already activated or in a banned state.
Consequently, the only rational thing to do in order to activate the account is to try and DELETE
the resource. And, in order to enable activation, an admin would have to PUT
an activation resource.
Now, the question that comes to mind is how do you distinguish a banned account from an already activated one. But since a ban could be seen as a resource too, you could create a /account/foo/ban
resource collection. In order to ban an account, probably for a fixed amount of time, you just POST
a resource under that collection, containing all the details of the ban.
Upvotes: 1
Reputation: 1789
How about coming up with a noun for the feature you want to modify - 'status' in this instance. This would then become a sub resource of the parent entity. So for your case I would model the URI as follows:
/api/accounts/{accountId}/status
If the 'update' semantics are idempotent then PUT would be most appropriate, else that would need to be a POST (e.g if nonces are involved and are invalidated by the service). The actual payload would include a descriptor for the new state.
Note, I pluralized 'accounts' since you can have multiple of those, but status is singular since your account can have only one state.
Upvotes: 18