7

I know that these type of questions have been asked before. I have solution for my problem and I want to know if I am breaking REST or HTTP principals anywhere.

In my system I have a resource called member which supports usual GET/POST/PUT operations. Member has a status of Active and Disabled. I need to model the operation of disabling the user. I understand why following would be a bad idea from REST perspective

POST api/member/john.smith/disable

I have read a solution to accept a resource that represents the request to disable a member, something like below

public class DisableMemberRequest
{
    public string Username {get; set;}
}

And then a POST on above resource

POST api/DisableMemberRequest

While this approach sounds reasonable, I feel this is not right in terms of clean API interfaces. It can be debatable whether the response of the above request should be a 200 OK or 201 Created or 202 Accepted.

I am thinking, I would crate a new resource called DisabledMember and a PUT on this resource would mean that particular member should be disabled as below

PUT api/disabledmember/john.smith

This looks to be a perfectly valid design from REST/HTTP perspective to me. But I am no expert and would like to validate this with people who have been doing this for long time.

EDIT

I am adding these details after interacting with fellow programmers on this page. The process of disabling the member is not only about setting a status flag on the member. There are other workflows that need to be triggered when a member is disabled.

Suhas
  • 7,919
  • 5
  • 34
  • 54

5 Answers5

4

One way that I like to do things like this is to define a resource that represents the set of disabled members. To disable a member, you add that member to the set of disabled members. It could look something like this.

POST /api/DisabledMembers
Content-Type: text/uri-list

http://example.org/api/members/john.smith

If you want to reverse the operation, you could do

POST /api/ActiveMembers
Content-Type: text/uri-list

http://example.org/api/members/john.smith

This approach has the benefit of the fact that doing GET /api/DisabledMembers would be a perfectly natural thing to do. Also, by using text/uri-list it becomes easy to disable/reactivate a set of members all at the same time.

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • Which is similar to what I'm planning to do. The only difference is you use `POST` in place of `PUT` – Suhas Jun 22 '13 at 03:22
  • @Suhas What media type would you PUT? I suppose you could PUT with an empty body and DELETE to reactivate. – Darrel Miller Jun 22 '13 at 13:21
  • The reason I use `PUT` is because the identifier of the resource that would be created on processing this request is known to client, or in other words you are `PUT`ting on a known URL. `POST` is usually used when client does not know the URL of the resource that would be created. – Suhas Jun 24 '13 at 21:46
  • @suhas PUT is perfectly valid. As you mention, it's easy fairly easy to construct the uri in advance, and it is idempotent. So, PUT is more representative of the semantics. The only weird thing is usually with PUT you are putting something you want to store. In your case, the action of doing the PUT is what is significant. There really is no need for a payload. – Darrel Miller Jun 24 '13 at 21:57
  • Let me get this right. Are you suggesting that `PUT` is recommended to have some payload while `POST` is ok without a payload? I am not very clear on that aspect. Is there any article/blog that talks more about this aspect? – Suhas Jun 25 '13 at 06:38
  • @Suhas both are fairly uncommon. However, as far as I know the HTTP spec has no objection to either. – Darrel Miller Jun 25 '13 at 11:13
3

Your first two suggestions both smell a little, because they have a verb in the URL. Good RESTful architecture defines noun-like resources only, as the HTTP protocol defines the set of verbs applicable to those resources.

The other suggestion is interesting, but PUT suggests you can then perform a GET to obtain a representation of the thing you just put there, which doesn't make a whole lot of sense in this context.

From what you're saying, there's a significant process to enabling or disabling a user's account and that you're not comfortable with that being a PUT or PATCH operation to simply "flip" a value from true to false. If this takes some time, has transient state and is likely to be something you want to be able to expose to API consumers so they are aware of the process, it makes sense to define the process itself as a kind of resource:

Start deactivation:

POST api/members/deactivations

Get the current state of a deactivation or report on activities that have taken place:

GET api/members/deactivations/john.smith

Cancel a deactivation in-progress (optional):

DELETE api/members/deactivations/john.smith

If you could reactivate an account, it could follow a similar pattern.

If you feel that there's not enough substance to these workflows to justify them as their own resources, or you just wouldn't know what to put in response to GET, then it suggests that the workflow isn't so significant that it can't simply be hidden from the API users and triggered as a side-effect of changing the user's active value.

Paul Turner
  • 38,949
  • 15
  • 102
  • 166
  • I think, what I was calling `DisableMemberRequest`, you are calling `deactivation`. I like the idea of using `DELETE` to cancel the process of deactivation. But again that is useful if your deactivation is a long running process. – Suhas Jun 22 '13 at 03:25
  • The difference is that a deactivation is clearly a "thing" that you can understand lives independently from other resources, but is still strongly related to `members`. – Paul Turner Jun 22 '13 at 08:00
2

Just answered a similar question in here.

The practical way of thinking or applying REST as the starting point (at least it works for me) is to think in the following ways:

1) Use only HTTP ‘GET/POST/PUT/DELETE’ as the way to model your domain ‘actions’ . Just like when you dealing with database, all your actions are mapped to CURD.

2) URI/URL is to identify resources only. Should never have any ‘actions’ in your URI.

3) The data exchanged should be in the body of the HTTP messages. Just to simplify the discussions, not getting into how to model the data itself

Tragedian’s solution looks clean.

Updated to address @Suhas' comments

REST is not about naming convention. It is all about how to think about the resources instead of ‘actions’ when designing REST API. Should always think about 'Nonce' like resource in URL/URI. You already have all the CURD actions that the domain actions should be mapped to and to manipulate the resources in the URL.

I like Tragedian's solution, just for the discussion sake, we can refactor Tragedian's solution with a similar set of nonce and different URL pattern to 'better' fit the different domain usage. The following may not be the best solution for the domain but they are equivalently RESTful.

Remove membership

  • DELETE api/membership/[member-id]/

Get membership status

  • GET api/membership/[member-id]/status/

Add membership

  • POST api/membership/[member-id]/

Updated to address the issue with "DisabledMember” as the resource

If using “PUT DisabledMember” to do ‘disable member’ as suggested by Suhas Then what will the following actions on ‘DisabledMember” resource mean?

DELETE DisabledMember → activate it again??

POST DisabledMember -> ??

GET DisabledMember – this is an easy one ☺

With this design, it actually “disguises” the action ‘disable’ in the resource. You may still can force fit it to do what you want but it wont be as Restful to me.

Community
  • 1
  • 1
Ming Chan
  • 1,938
  • 11
  • 21
  • I think the only difference between my second solution and tragedian's solution is - he has a better naming convention. – Suhas Jun 22 '13 at 05:41
  • REST is not about naming convention. It is all about how to think about the resources instead of ‘actions’ when designing REST API. Should always think about 'Nonce' like resource in URL/URI. You already have all the CURD actions that the domain actions should be mapped to and to manipulate the resources in the URL. – Ming Chan Jun 22 '13 at 18:40
  • I get your point on designing around resource. But I do not see a comment on my third design around introducing a new resource called `DisabledMember`. Are there any problems with that design? – Suhas Jun 24 '13 at 08:04
  • With 'DisabledMember' design, it actually “disguises” the action ‘disable’ in the resource. You may still can force fit it to do what you want but it wont be as Restful to me. – Ming Chan Jun 24 '13 at 17:56
  • Does every resource have to support every HTTP action? `DELETE/POST` on `DisabledMember` would just return `HTTP 405 Not Allowed` – Suhas Jul 08 '13 at 17:12
  • It does not have to but it will be more for the business logic reasons; for example, to disallow Delete, it could be that it is not allow to 'remove' this particular resource after it is created. I typically think through the resource name by considering all the CURD verbs to help making my design choice. – Ming Chan Jul 08 '13 at 17:43
  • When I said that I meant "for business reasons" only. E.g. If I disallow `DELETE` on `DisabledMember` it would be for business reasons. – Suhas Jul 08 '13 at 21:21
0

Member has a status of Active and Disabled

So status is a property of Member entity/resource; in that case why you don't want to use simply PUT method on Member resource with status set to Disabled?

maks
  • 5,911
  • 17
  • 79
  • 123
  • 2
    Member has lot of other fields which clients may want to update. They use put in that situation. These updates usually do not result in any other workflow being triggered. They are simple updates to our data store. But disabling a member is a complex workflow and as such needs to be separated from member update as a concept. – Suhas Jun 21 '13 at 23:25
  • you have a resource under members/{someId}. You use GET for retrieving that resource, DELETE - for deleting those resource, PUT - for updating those resource. POST method is free, so you can use it to activate deactivate your member – maks Jun 21 '13 at 23:32
  • if you have several cases of starting workflow process, that can be identified by different parameters to POST method – maks Jun 21 '13 at 23:44
  • 1
    Do you mean query string? I doubt I would use query strings on post to send in parameters. And one post to rule them all looks like breach of SRP to me. – Suhas Jun 22 '13 at 03:26
0

If it's a short process to disable the user, why not use HTTP PATCH?

See this answer to a similar question

Community
  • 1
  • 1
Corey Cole
  • 977
  • 9
  • 18