HTTP response code for POST when resource already

2019-01-05 06:42发布

I'm building a server that allows clients to store objects. Those objects are fully constructed at client side, complete with object IDs that are permanent for the whole lifetime of the object.

I have defined the API so that clients can create or modify objects using PUT:

PUT /objects/{id} HTTP/1.1
...

{json representation of the object}

The {id} is the object ID, so it is part of the Request-URI.

Now, I'm also considering allowing clients to create the object using POST:

POST /objects/ HTTP/1.1
...

{json representation of the object, including ID}

Since POST is meant as "append" operation, I'm not sure what to do in case the object is already there. Should I treat the request as modification request or should I return some error code (which)?

标签: http rest
15条回答
欢心
2楼-- · 2019-01-05 07:20

I don't think you should do this.

The POST is, as you know, to modify the collection and it's used to CREATE a new item. So, if you send the id (I think it's not a good idea), you should modify the collection, i.e., modify the item, but it's confusing.

Use it to add an item, without id. It's the best practice.

If you want to capture an UNIQUE constraint (not the id) you can response 409, as you can do in PUT requests. But not the ID.

查看更多
我想做一个坏孩纸
3楼-- · 2019-01-05 07:22

Personally I go with the WebDAV extension 422 Unprocessable Entity.

REST Patterns describes it as

The 422 Unprocessable Entity status code means the server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.

查看更多
三岁会撩人
4楼-- · 2019-01-05 07:22

What about returning a 418?

Because the client ask to persist an entity that already exists on the server, the server finally gets mad and think he's a teapot and return: 418 I'm a teapot.

References:

查看更多
太酷不给撩
5楼-- · 2019-01-05 07:29

I think for REST, you just have to make a decision on the behavior for that particular system in which case, I think the "right" answer would be one of a couple answers given here. If you want the request to stop and behave as if the client made a mistake that it needs to fix before continuing, then use 409. If the conflict really isn't that important and want to keep the request going, then respond by redirecting the client to the entity that was found. I think proper REST APIs should be redirecting (or at least providing the location header) to the GET endpoint for that resource following a POST anyway, so this behavior would give a consistent experience.

EDIT: It's also worth noting that you should consider a PUT since you're providing the ID. Then the behavior is simple: "I don't care what's there right now, put this thing there." Meaning, if nothing is there, it'll be created; if something is there it'll be replaced. I think a POST is more appropriate when the server manages that ID. Separating the two concepts basically tells you how to deal with it (i.e. PUT is idempotent so it should always work so long as the payload validates, POST always creates, so if there is a collision of IDs, then a 409 would describe that conflict).

查看更多
贪生不怕死
6楼-- · 2019-01-05 07:30

According to RFC 7231, a 303 See Other MAY be used If the result of processing a POST would be equivalent to a representation of an existing resource.

查看更多
家丑人穷心不美
7楼-- · 2019-01-05 07:32

Late to the game maybe but I stumbled upon this semantics issue while trying to make a REST API.

To expand a little on Wrikken's answer, I think you could use either 409 Conflict or 403 Forbidden depending on the situation - in short, use a 403 error when the user can do absolutely nothing to resolve the conflict and complete the request (e.g. they can't send a DELETE request to explicitly remove the resource), or use 409 if something could possibly be done.

10.4.4 403 Forbidden

The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.

Nowadays, someone says "403" and a permissions or authentication issue comes to mind, but the spec says that it's basically the server telling the client that it's not going to do it, don't ask it again, and here's why the client shouldn't.

As for PUT vs. POST... POST should be used to create a new instance of a resource when the user has no means to or shouldn't create an identifier for the resource. PUT is used when the resource's identity is known.

9.6 PUT

...

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI,

it MUST send a 301 (Moved Permanently) response; the user agent MAY then make its own decision regarding whether or not to redirect the request.

查看更多
登录 后发表回答