119

I keep a key-value storage in the server for the client. If the user sends key "k1", then I upsert it to the database. Is this considered POST or PUT?

Also I have another operation that removes all existing keys and adds the new key. Is this POST or PUT because it clears records and adds a new one.

Henke
  • 4,445
  • 3
  • 31
  • 44
Jimmy
  • 10,427
  • 18
  • 67
  • 122

6 Answers6

129

If the user sends key k1, and I upsert it to the database, is this considered POST or PUT?

According to the HTTP specification:

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

I therefore think that the use of PUT for an insert or update is perfectly legitimate, provided that in both cases the URI is known in advance. If you're using the key as part of the URI (as k1 in http://www.somewhere.com/resources/k1) this should be the case. To be ideally RESTful, however, a GET to the same URL should also allow you to download the resource.

I have another operation that removes all existing keys and adds the new key. Is this a POST or PUT operation, since it clears records and adds a new one?

I don't think this operation could be considered RESTful since it does two things. It seems to be providing a macro to satisfy the needs of a particular client, rather than simple access to data. A standard RESTful design would be:

  1. Getting a list of keys by sending a GET to the parent URL. In the example above, that would be http://www.somewhere.com/resources;
  2. Deleting each of those keys by sending a DELETE to http://www.somewhere.com/resources/k1;
  3. Adding the replacement by sending a PUT to http://www.somewhere.com/resources/k2.

It's less clear cut, but I think it would also be legitimate to delete all resources by sending a single DELETE request to http://www.somewhere.com/resources.

jonschlinkert
  • 10,872
  • 4
  • 43
  • 50
Polly Shaw
  • 2,932
  • 1
  • 15
  • 21
  • 4
    Wouldn't DELETE on http://www.somewhere.com/resources be a possible replacement for the steps 1 and 2? – dmigo Feb 07 '19 at 08:48
  • 2
    1, 2, 3. This is why I feel like these things are a little bit outdated. If I've to delete 100 things at the same time, should I make 100 DELETE requests? I feel like a single socket connection or something like that should just work based on events. – Faheem May 08 '19 at 08:10
  • upvoted! what is your opinion about PATCH request then? can that be used for this case – PirateApp Jan 03 '20 at 04:21
  • So if `PUT` will both create or update... whats the point of making a `POST` route for the resource – nawlbergs Mar 29 '21 at 15:53
  • 1
    `POST` shall be used if URI is not known i.e. when there is a FactoryPattern used that is creating a UUID or other action required for constructing resource which later could also be part of the URI - might be combined with code 201. `PATCH` could be also a substitute to `PUT` but usually only used for partially updating / patching a resource - shall leave non-mentioned information untouched. – David Renner May 17 '21 at 22:03
  • Just to clarify that, according to the [HTTP specs](https://www.w3.org/Protocols/), the RFC 2616 document was replaced by a series of documents that define the HTTP/1.1 Protocol and therefore it shouldn't be used anymore. HTTP method definitions are now listed under the [rfc7231 - section 4.3](https://datatracker.ietf.org/doc/html/rfc7231#section-4.3) – prietosanti Sep 09 '21 at 13:13
14

According to MDN Web Docs :

PUT

The HTTP PUT request method creates a new resource or replaces a representation of the target resource with the request payload.

The difference between PUT and POST is that PUT is idempotent: calling it once or several times successively has the same effect (that is no side effect), whereas successive identical POST requests may have additional effects, akin to placing an order several times.

Syntax

PUT /new.html HTTP/1.1

Example

Request

PUT /new.html HTTP/1.1
Host: example.com
Content-type: text/html
Content-length: 16

<p>New File</p>

Responses

If the target resource does not have a current representation and the PUT request successfully creates one, then the origin server must inform the user agent by sending a 201 (Created) response.

HTTP/1.1 201 Created 
Content-Location: /new.html

If the target resource does have a current representation and that representation is successfully modified in accordance with the state of the enclosed representation, then the origin server must send either a 200 (OK) or a 204 (No Content) response to indicate successful completion of the request.

HTTP/1.1 204 No Content 
Content-Location: /existing.html
Y Y
  • 443
  • 6
  • 16
3

If the definition of an upsert is a mix of new records with existing records (to update).

Refering to: https://restfulapi.net/rest-put-vs-post/

PUT needs to be idempotent. This means if you PUT the same payload a second time the system state should not be changed.

If the intended payload is a mix of new and existing and the expected behavior would be to create more new records the second time around then it would seem 'upsert' would line up more closely with POST.

We strive to create mistake tolerant APIs. If you cannot make the PUT idempotent and they must use it they could corrupt the system. On the other hand POST is not expected to be idempotent, so if you sent update-only data (over and over) in the payload (even though this technically violates the idempotency rule for POST because it did not change the state of the system by adding records on subsequent calls) the system would (probably) not be corrupted.

  • The spec says PUT "can" add new items and "must" be idempotent
  • It says POST "must" add new items and is not idempotent

If you really want to implement an upsert neither is perfect, but if mistakes cause corruption on PUT the API is to blame (its supposed to be idempotent) whereas corruption on POST is "I told you so".

I also like to think about what the API consumer will be looking for. Commonly a UI dev working on a new screen will be looking to add the records the user has added in the UI. He'll be looking for a POST first, then discover that it also handles the PUT side of the equation.

So, neither, but if you have to choose, choose POST.

Rob Henry
  • 47
  • 2
  • 2
    This answer makes no sense. Upserts are idempotent. The first time it either creates or updates the resources. Every time after that it does nothing. – MikeTwo Aug 25 '21 at 17:30
  • 1
    @MikeTwo Oh really? When the first PUT request is dispatched it does not include an id, and if for whatever reason the request is repeated it will create another resource, which is anything but idempotent. – elad.chen Jan 30 '22 at 12:49
  • Upserts are not necessarily idempotent. Update part can be cumulative operations, such as increment, decrement, adding a new event to the event history for the key. – QuestionDriven Jul 05 '23 at 06:13
2

Polly Shaw's answer is correct, but I would like to mention that given that the message might very likely be incomplete (missing the ID when the resource is not yet created), a PATCH verb would be slightly more correct.

https://www.rfc-editor.org/rfc/rfc5789

This is extremely fine tuning.

Community
  • 1
  • 1
ecoologic
  • 10,202
  • 3
  • 62
  • 66
0

The idea behind upsert operation is that clients have information about/decide on data structure and sending data with key value. So request model for upsert operation is very similar to update operation with key included as the example below:

/customers/jimmy

The expected method for updating an existing record is PUT. So your choice should be PUT.

POST is generally used for inserting a new record with a brand new content like in the example below:

POST /customers HTTP/1.1
Content-Type: ...
Content-Length: ...
Host: server.yourdomain.com
Accept: ...
User-Agent: ...

id      jimmy
name    jimmy
Occupation   Stackoverflower

So in your case you do not need any POST operation because PUT for upsert operation also covers that.

Here the critical question about upsert is how likely you trust your client about upsert operation. If a client desires to insert a new record with an existing key what happens? In your case you should handle this request as an update because both insert and update requests come to the same api and you have an existing record. This is the question to be answered on your side about design.

Tahsin Turkoz
  • 4,356
  • 1
  • 27
  • 18
-5

If you mix everything, you're probably not doing REST. From RESTful Web services: The basics POST and PUT have distinct usage scenario:

  • To create a resource on the server, use POST.
  • To retrieve a resource, use GET.
  • To change the state of a resource or to update it, use PUT.
  • To remove or delete a resource, use DELETE.

So consider POST as posting a new ticket to a blog and PUT to change an existing value.

Removing should be done as a distinctive operation with the DELETE verb. As "remove all" before update doesn't sound like a good idea.

shaedrich
  • 5,457
  • 3
  • 26
  • 42
Édouard Lopez
  • 40,270
  • 28
  • 126
  • 178
  • 7
    I do think there are scenarios where 'upsert' is valid, like flagging if a user 'viewed' a resource i.e. I want this 'flagged/checked/ticked' regardless of it's previous state – profMamba Jan 10 '14 at 05:01
  • 3
    What is wrong with this answer for 5 down votes? A caller may call get and then put or post depending on outcome. – RuntimeException Apr 19 '18 at 13:04
  • @RuntimeException I guess it is because, same thing was told in question and asked a different scenario when it is upsert (when one endpoint should update a resource but create if that resource doesn't exists). So instead of answering question, it told same thing that was already clear. – Hafiz Sep 14 '18 at 14:42
  • @RuntimeException, also its slightly misleading to equate HTTP verbs to CRUD. PUT can also Create. PATCH is another way to Update. – Kindread May 10 '19 at 11:05
  • 2
    @RuntimeException I think the other reason this answer is not useful is it is extremely difficult to make two sequential operations idempotent. Another client can come in between the GET and PUT and screw up your state. I think you want to move the implementation of upsert as close to the final database as you can. Separate GET/PUT or GET/POST us unlikely to work in a highly parallel system. – Chris Warth Dec 05 '19 at 19:34