在 REST 中是 POST 还是 PUT 最适合逆向操作?

我在服务器中为客户端保留了一个键值存储。如果用户发送键“ k1”,那么我将它插入到数据库中。这被认为是 POST还是 PUT

此外,我还有另一个操作,删除所有现有的关键,并添加新的关键。这是 POST还是 PUT,因为它清除记录并添加一个新的。

53460 次浏览

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.

If the user send key "k1" then 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.

Also I have another operation which remove all existing keys and add the new key, is this POST or PUT because it clear records and add new one.

I don't think this operation could be considered RESTful because 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.

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.

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.

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.

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