304

I want to design my rest endpoint with the appropriate method for the following scenario.

There is a group. Each group has a status. The group can be activated or inactivated by the admin.

Should I design my end point as

PUT /groups/api/v1/groups/{group id}/status/activate

OR

PATCH /groups/api/v1/groups/{group id}

with request body like 
{action:activate|deactivate}
halfer
  • 18,701
  • 13
  • 79
  • 158
java_geek
  • 15,768
  • 29
  • 82
  • 105
  • 1
    Both are fine. But do take a look at the RFC for the JSON PATCH format (http://tools.ietf.org/html/rfc6902). PATCH expects to get some kind of diff/patch document for the payload (and raw JSON is not one of them). – Jørn Wildt Jun 16 '14 at 10:49
  • 1
    @JørnWildt no, PUT would be a horrible choice. What are you putting there? PATCH is the only sensible option. Well, in this case you could use the PATCH format presented in the question, and just use the PUT method; the PUT example is just wrong. – thecoshman Jun 17 '14 at 13:01
  • 3
    There is nothing wrong in exposing one or more properties as standalone resources that a client can GET and modify with PUT. But, yes, the URL should then be /groups/api/v1/groups/{group id}/status to which you can PUT "active" or "inactive" or GET to read the current state. – Jørn Wildt Jun 18 '14 at 07:58
  • 5
    Here's a good explanation of how PATCH should really be used: http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/ – rishat Dec 07 '14 at 21:21
  • both are not fine, its a mistake to have version (v1) mentioned in the url IMO. – Hector Jun 28 '15 at 07:55
  • 5
    "`activate`" is not adequate RESTful construction. You're probably trying to update the `status` to "active" or "deactive". in which case you can PATCH to `.../status` with the "active" or "deactive" string in the body. Or if you are trying to update a boolean at `status.active`, you can PATCH to `.../status/active` with the boolean in the body – Augie Gardner Jan 12 '17 at 07:35

6 Answers6

365

The PATCH method is the correct choice here as you're updating an existing resource - the group ID. PUT should only be used if you're replacing a resource in its entirety.

Further information on partial resource modification is available in RFC 5789. Specifically, the PUT method is described as follows:

Several applications extending the Hypertext Transfer Protocol (HTTP) require a feature to do partial resource modification. The existing HTTP PUT method only allows a complete replacement of a document. This proposal adds a new HTTP method, PATCH, to modify an existing HTTP resource.

Judge Mental
  • 5,091
  • 15
  • 20
Luke Peterson
  • 7,732
  • 8
  • 41
  • 45
  • 1
    To be fair, you could PUT the string 'activate' or 'deactivate' to the resource. As there (seems) to only be the one thing to toggle, completely replacing it is not such a huge deal. And it does allow for a (insignificantly) smaller request. – thecoshman Jun 17 '14 at 13:04
  • 39
    It is important to note that RFC 5789 is still in proposal phase and has not been officially accepted and is currently flagged as 'irrata exist'. This 'best practice' is highly debated and technically PATCH is not yet part of the HTTP standard. – fishpen0 Oct 05 '15 at 21:30
  • 4
    Just my 2 cents a few years later: you could consider the status itself to be a resource, and if so, using PUT against /status would technically be replacing the status resource at that end point. – Jono Stewart Nov 21 '17 at 13:22
  • 4
    I would dare to argue against the docs, even though it's "the" RFC. The docs state that you should use PATCH to modify just a part of a resource, but it omitted the important thing that PATCH method is defined as a non-idempotent method. Why? If the PUT method was created with the update/replacement of the whole resource in mind, then why wasn't PATCH method created as an idempotent method like PUT, if its purpose was to just update the part of a resource? To me, it looks more of a difference in idempotency of update, like "a=5" (PUT) and "a=a+5" (PATCH). Both can update the entire resource. – Mladen B. Mar 29 '18 at 14:56
200

The R in REST stands for resource

(Which isn't true, because it stands for Representational, but it's a good trick to remember the importance of Resources in REST).

About PUT /groups/api/v1/groups/{group id}/status/activate: you are not updating an "activate". An "activate" is not a thing, it's a verb. Verbs are never good resources. A rule of thumb: if the action, a verb, is in the URL, it probably is not RESTful.

What are you doing instead? Either you are "adding", "removing" or "updating" an activation on a Group, or if you prefer: manipulating a "status"-resource on a Group. Personally, I'd use "activations" because they are less ambiguous than the concept "status": creating a status is ambiguous, creating an activation is not.

  • POST /groups/{group id}/activation Creates (or requests the creation of) an activation.
  • PATCH /groups/{group id}/activation Updates some details of an existing activation. Since a group has only one activation, we know what activation-resource we are referring to.
  • PUT /groups/{group id}/activation Inserts-or-replaces the old activation. Since a group has only one activation, we know what activation-resource we are referring to.
  • DELETE /groups/{group id}/activation Will cancel, or remove the activation.

This pattern is useful when the "activation" of a Group has side-effects, such as payments being made, mails being sent and so on. Only POST and PATCH may have such side-effects. When e.g. a deletion of an activation needs to, say, notify users over mail, DELETE is not the right choice; in that case you probably want to create a deactivation resource: POST /groups/{group_id}/deactivation.

It is a good idea to follow these guidelines, because this standard contract makes it very clear for your clients, and all the proxies and layers between the client and you, know when it is safe to retry, and when not. Let's say the client is somewhere with flaky wifi, and its user clicks on "deactivate", which triggers a DELETE: If that fails, the client can simply retry, until it gets a 404, 200 or anything else it can handle. But if it triggers a POST to deactivation it knows not to retry: the POST implies this.
Any client now has a contract, which, when followed, will protect against sending out 42 emails "your group has been deactivated", simply because its HTTP-library kept retrying the call to the backend.

Updating a single attribute: use PATCH

PATCH /groups/{group id}

In case you wish to update an attribute. E.g. the "status" could be an attribute on Groups that can be set. An attribute such as "status" is often a good candidate to limit to a whitelist of values. Examples use some undefined JSON-scheme:

PATCH /groups/{group id} { "attributes": { "status": "active" } }
response: 200 OK

PATCH /groups/{group id} { "attributes": { "status": "deleted" } }
response: 406 Not Acceptable

Replacing the resource, without side-effects use PUT.

PUT /groups/{group id}

In case you wish to replace an entire Group. This does not necessarily mean that the server actually creates a new group and throws the old one out, e.g. the ids might remain the same. But for the clients, this is what PUT can mean: the client should assume he gets an entirely new item, based on the server's response.

The client should, in case of a PUT request, always send the entire resource, having all the data that is needed to create a new item: usually the same data as a POST-create would require.

PUT /groups/{group id} { "attributes": { "status": "active" } }
response: 406 Not Acceptable

PUT /groups/{group id} { "attributes": { "name": .... etc. "status": "active" } }
response: 201 Created or 200 OK, depending on whether we made a new one.

A very important requirement is that PUT is idempotent: if you require side-effects when updating a Group (or changing an activation), you should use PATCH. So, when the update results in e.g. sending out a mail, don't use PUT.

jhhwilliams
  • 1,357
  • 13
  • 22
berkes
  • 25,081
  • 21
  • 107
  • 188
  • 3
    This was very informative to me. "This pattern is useful when the "activation" of a group has side-effects" - How come this pattern is useful, specifically in regards to when actions have side effects, as opposed to the OP initial endpoints – Abdul Aug 19 '16 at 12:11
  • 1
    @Abdul, the pattern is useful for a lot of reasons, but wrt side-effects, it should be very clear to a client, what effects an action has. When, say, an iOS app decides to send the entire addressbook as "contacts" it should be extremely clear what side-effects the create, update, delete etc. of a Contact has. To avoid mass-mailing all contacts, for example. – berkes Sep 28 '16 at 06:59
  • Thank you for setting me straight. I mistakenly understood that if I wanted to do an update on everything except for the ID I should be using PATCH instead of PUT. – kojow7 Apr 22 '17 at 06:12
  • 1
    In RESTfull PUT can also change the entities Identity - For example the PrimaryKey ID where it could cause a parallel request to fail. (for example updating the entire entity needs to delete some rows and add new ones, hence creating new entities) Where PATCH must never be able to do that, allowing for unlimited number of PATCH requests without affecting other "applications" – Piotr Kula Jun 28 '17 at 11:57
  • 2
    Very helpful answer. Thanks! I would also add a comment, just like in Luke's answer, pointing out that the difference between PUT/PATCH is not just the whole/partial update, it's also the idempotency that's different. This wasn't a mistake, it was an intentional decision and I think not a lot of people take this into the consideration, when deciding the HTTP method's usage. – Mladen B. Mar 29 '18 at 14:59
  • 1
    I agree and disagree. RESTful API shouldn't reflect your domain. They tend to model the applications' use cases more than the business. There is a reason why RESTful apis follow RFC 2616. As a consumer I have no clue what the "side effects" of your business operations are. All I know is that your HTTP VERBS should reflect the operation on the RESOURCE. Therefore if a DELETE is idempotent, it means than the operation on the RESOURCE is so. Not the "side effects". Sending emails are not violations of "idempotency". That's a business concern, not a RESTful api. – Pepito Fernandez May 07 '18 at 20:28
  • An "activate" might not be a thing, but an "activate service" is most definitely a thing. If your `rel` is service, then your comment about "verbs" in URLs is irrelevant. – rich remer Nov 08 '18 at 21:29
  • @richremer I disagree. Services are not Nouns in practice. Technically an `ActivateService` is a noun, true. But in practice it is just a verb hiding behind a noun. Same for `Agent` (ActivateAgent), `Maker` (ActiveMaker), `Factory` (ActivateFactory) or other service-alike models. A REST interface that allows interaction with such verb-ishms is really an RPC interface decorated as REST. It has all the downsides of REST, and hardly the benefits. Furthermore: IMO Services are internal implementation details and should not be exposed. – berkes Nov 09 '18 at 14:34
  • I'm not sure I understand what you mean by that last bit. What's the point of the long-standing "service" relationship if services should not be exposed? – rich remer Nov 09 '18 at 18:27
  • 1
    @richremer services, like models, are internal abstractions. Just as it is a poor abstraction to require a 1-1 relation between REST-endpoints-and-ORM-models or even database tables, it is poor abstraction to expose Services. The outside would, your API, must communicate domain models. How you implement them internally is of no concern to the API. You should be free to move from a ActivationService to a CQRS based activation flow, without having to change your API. – berkes Nov 13 '18 at 16:30
  • It's a poor abstraction to attempt to map domain models and REST interfaces 1-to-1, but we can agree to disagree. Though, I still would like to understand what you think of the role of `rel="service"`. – rich remer Nov 13 '18 at 20:17
  • @richremer I'm not sure if I understand you. But `rel=service` is used in rfc5023 (Atom) to link to the Services document. In a RESTfull API, there is no place for Services, since it is about Resources. Sure, you can link to an RPC endpoint from a REST-ful response, but that smells really bad and gives hardly any benefits, IMO. – berkes Nov 16 '18 at 14:35
  • "A very important requirement is that PUT is idempotent: if you require side-effects when updating a Group (or changing an activation), you should use PATCH." Sorry but PUT *has* side effects, since it updates a resource. Having no side effects is defined as being "safe" in RFC 7231, and PUT method is *not* safe, only GET, HEAD, OPTIONS, and TRACE methods are in the RFC. – Maggyero Feb 11 '19 at 07:05
  • 1
    @Maggyero `A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request. Of the request methods defined by this specification, PUT, DELETE, and safe request methods are idempotent.`. So, no it is not safe. But it should be idempotent! – berkes Feb 11 '19 at 16:20
  • 1
    You are using 406 in a **very** stange way. 406 means that the server was unable to send a response back to the client because the response cannot be formatted into any of the formats specified by the client in its accept header. 406 does _not_ imply that the requested operation failed, _only_ that the server was unable to send back a response. E.g. you could request a file upload to the server, the file upload succeeds, and you could still get a 406 response. See: [what-is-406-not-acceptable-response](https://stackoverflow.com/questions/14251851/what-is-406-not-acceptable-response-in-http). – AnorZaken Mar 10 '19 at 15:00
13

I would recommend using PATCH, because your resource 'group' has many properties but in this case, you are updating only the activation field(partial modification)

according to the RFC5789 (https://tools.ietf.org/html/rfc5789)

The existing HTTP PUT method only allows a complete replacement of a document. This proposal adds a new HTTP method, PATCH, to modify an existing HTTP resource.

Also, in more details,

The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource
identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the
origin server, and the client is requesting that the stored version
be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the
origin server should be modified to produce a new version. The PATCH method affects the resource identified by the Request-URI, and it
also MAY have side effects on other resources; i.e., new resources
may be created, or existing ones modified, by the application of a
PATCH.

PATCH is neither safe nor idempotent as defined by [RFC2616], Section 9.1.

Clients need to choose when to use PATCH rather than PUT. For
example, if the patch document size is larger than the size of the
new resource data that would be used in a PUT, then it might make
sense to use PUT instead of PATCH. A comparison to POST is even more difficult, because POST is used in widely varying ways and can
encompass PUT and PATCH-like operations if the server chooses. If
the operation does not modify the resource identified by the Request- URI in a predictable way, POST should be considered instead of PATCH
or PUT.

The response code for PATCH is

The 204 response code is used because the response does not carry a message body (which a response with the 200 code would have). Note that other success codes could be used as well.

also refer thttp://restcookbook.com/HTTP%20Methods/patch/

Caveat: An API implementing PATCH must patch atomically. It MUST not be possible that resources are half-patched when requested by a GET.

Clojurevangelist
  • 503
  • 7
  • 10
7

Since you want to design an API using the REST architectural style you need to think about your use cases to decide which concepts are important enough to expose as resources. Should you decide to expose the status of a group as a sub-resource you could give it the following URI and implement support for both GET and PUT methods:

/groups/api/groups/{group id}/status

The downside of this approach over PATCH for modification is that you will not be able to make changes to more than one property of a group atomically and transactionally. If transactional changes are important then use PATCH.

If you do decide to expose the status as a sub-resource of a group it should be a link in the representation of the group. For example if the agent gets group 123 and accepts XML the response body could contain:

<group id="123">
  <status>Active</status>
  <link rel="/linkrels/groups/status" uri="/groups/api/groups/123/status"/>
  ...
</group>

A hyperlink is needed to fulfill the hypermedia as the engine of application state condition of the REST architectural style.

1

I would generally prefer something a bit simpler, like activate/deactivate sub-resource (linked by a Link header with rel=service).

POST /groups/api/v1/groups/{group id}/activate

or

POST /groups/api/v1/groups/{group id}/deactivate

For the consumer, this interface is dead-simple, and it follows REST principles without bogging you down in conceptualizing "activations" as individual resources.

rich remer
  • 2,965
  • 1
  • 29
  • 39
0

One possible option to implement such behavior is

PUT /groups/api/v1/groups/{group id}/status
{
    "Status":"Activated"
}

And obviously, if someone need to deactivate it, PUT will have Deactivated status in JSON.

In case of necessity of mass activation/deactivation, PATCH can step into the game (not for exact group, but for groups resource:

PATCH /groups/api/v1/groups
{
    { “op”: “replace”, “path”: “/group1/status”, “value”: “Activated” },
    { “op”: “replace”, “path”: “/group7/status”, “value”: “Activated” },
    { “op”: “replace”, “path”: “/group9/status”, “value”: “Deactivated” }
}

In general this is idea as @Andrew Dobrowolski suggesting, but with slight changes in exact realization.

Ivan Sokalskiy
  • 761
  • 6
  • 13