35

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?

3
  • I don't think that it's an "RPC" design. It's a "Message"-based design. Although, why not POST in the first example? Commented Feb 15, 2014 at 8:32
  • It seems to be standard to use POST as non-idempotent method. I'm still not sure what is the best design pattern for such "command" cases. Commented Mar 2, 2016 at 8:09
  • 2
    I found this interesting talk about "REST-Ful API Design" youtu.be/oG2rotiGr90 and use rules it defines e.g. PUT/PATCH for actions like "activate", "open", "install" and so on. Commented Dec 12, 2016 at 7:56

4 Answers 4

18

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Interesting approach. However in this way we will introduce something new from the functional point of view (a new property?), thus increase complexity. However, as I said gut point when designing the core domain model.
Its old thread but PUT "should" have body
5

PATCH is the most appropriate method in this case. Please find more at RESTful URL for "Activate"

1 Comment

The problem with this approach is that it hides the semantic in the body of the request. I wouldn't do it even if it might be correct from the puristic design point of view.
4

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.

7 Comments

I'm confused as to why this answer was down voted. I've seen this used before and it seemed appropriate.
Neerja, I think there is a reluctance to use query (?) parameters in this way, but instead to limit there use to selection criteria/filters.
We should limit query parameters to filtering
I don't think that's a good answer. Firstly, PUT should "replace all current representations of the target resource with the request payload" (tools.ietf.org/html/rfc7231#section-4.1) which means you should PUT ALL the payload, not just single status field. You'd better suggest PATCH.
Secondly. "GET, HEAD, OPTIONS, and TRACE methods are defined to be safe" (tools.ietf.org/html/rfc7231#section-4.2.1) which means user does not have to care much about sending them - he should be assured that his actions with GET requests will not do any harm. Request with ?activate=false params WILL do harm. In contrast, POST, PUT, PATCH, DELETE aren't safe and while user sending them he must think of he is responsible for any harm it'll do.
|
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.