Should I use PATCH or PUT in my REST API? [closed]
Asked Answered
D

6

344

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}
Deadly answered 16/6, 2014 at 10:44 Comment(6)
Both are fine. But do take a look at the RFC for the JSON PATCH format (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).Survey
@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.Cassady
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.Survey
Here's a good explanation of how PATCH should really be used: williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiotInfrastructure
both are not fine, its a mistake to have version (v1) mentioned in the url IMO.Wilscam
"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 bodyTasse
H
412

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.

Hardwick answered 16/6, 2014 at 10:48 Comment(5)
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.Cassady
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.Riddick
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.Kr
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.Nomism
Another option is create a new endpoint for update the required field/s. For example in case to change the password, PUT /users/{userId}/password. If anyone think that I'm wrong please let me know.Drippy
H
235

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.

Herr answered 31/5, 2016 at 11:36 Comment(15)
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 endpointsShire
@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.Herr
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.Ummersen
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"Claxton
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.Nomism
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.Craunch
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.Soubise
@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.Herr
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?Soubise
@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.Herr
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".Soubise
@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.Herr
"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.Spectrohelioscope
@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!Herr
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.Nucleotidase
S
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://www.rfc-editor.org/rfc/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.

Steel answered 20/6, 2016 at 12:13 Comment(0)
S
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.

Strop answered 19/4, 2016 at 19:41 Comment(0)
M
3

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.

Malaysia answered 7/1, 2020 at 20:54 Comment(1)
Great use of RFC6902 for standard JSON patch ! For me this is the best answerPogue
S
0

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.

Soubise answered 25/7, 2018 at 0:7 Comment(2)
"When possible, resource URIs should be based on nouns (the resource) and not verbs (the operations on the resource)." ~ learn.microsoft.com/en-us/azure/architecture/best-practices/…Borrero
If you really think so, you can use "activation" and "deactivation". The argument still holds. Service (i.e., those whose Link headers might have rel=service) resources are a good fit here.Chadwick

© 2022 - 2024 — McMap. All rights reserved.