1001
votes

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)?

17
As of June 2016 FB blatantly sets 200 on registration when email existsGreen
Github API returns 422 when trying to create a resource (team/repo) with a name that is already in useKen
It depends if you consider the existence of the object an error or not. If you process the append, 200 or 204 are the most appropriate response codes.Suncat2000
In summary its a toss up between 409 Conflict and 422 Unprocessable Entity - I think the weight of answers here points to 409 though and certainly from a human perspective is more readily understandabledanday74
I use 409 for this and 422 for bad forms only.Anthony O

17 Answers

1266
votes

My feeling is 409 Conflict is the most appropriate, however, seldom seen in the wild of course:

The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.

Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.

126
votes

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.

103
votes

Personally I go with the WebDAV extension 422 Unprocessable Entity.

According to RFC 4918

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.

85
votes

It's all about context, and also who is responsible for handling duplicates in requests (server or client or both)


If server just point the duplicate, look at 4xx:

  • 400 Bad Request - when the server will not process a request because it's obvious client fault
  • 409 Conflict - if the server will not process a request, but the reason for that is not the client's fault
  • ...

For implicit handling of duplicates, look at 2XX:

  • 200 OK
  • 201 Created
  • ...

if the server is expected to return something, look at 3XX:

  • 302 Found
  • 303 See Other
  • ...

when the server is able to point the existing resource, it implies a redirection.


If the above is not enough, it's always a good practice to prepare some error message in the body of the response.

30
votes

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.

16
votes

I would go with 422 Unprocessable Entity, which is used when a request is invalid but the issue is not in syntax or authentication.

As an argument against other answers, to use any non-4xx error code would imply it's not a client error, and it obviously is. To use a non-4xx error code to represent a client error just makes no sense at all.

It seems that 409 Conflict is the most common answer here, but, according to the spec, that implies that the resource already exists and the new data you are applying to it is incompatible with its current state. If you are sending a POST request, with, for example, a username that is already taken, it's not actually conflicting with the target resource, as the target resource (the resource you're trying to create) has not yet been posted. It's an error specifically for version control, when there is a conflict between the version of the resource stored and the version of the resource requested. It's very useful for that purpose, for example when the client has cached an old version of the resource and sends a request based on that incorrect version which would no longer be conditionally valid. "In this case, the response representation would likely contain information useful for merging the differences based on the revision history." The request to create another user with that username is just unprocessable, having nothing to do with version control.

For the record, 422 is also the status code GitHub uses when you try to create a repository by a name already in use.

11
votes

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.

8
votes

"302 Found" sounds logical for me. And the RFC 2616 says that it CAN be answered for other requests than GET and HEAD (and this surely includes POST)

But it still keeps the visitor going to this URL to get this "Found" resource, by the RFC. To make it to go directly to the real "Found" URL one should be using "303 See Other", which makes sense, but forces another call to GET its following URL. On the good side, this GET is cacheable.

I think that I would use "303 See Other". I dont know if I can respond with the "thing" found in the body, but I would like to do so to save one roundtrip to the server.

UPDATE: After re-reading the RFC, I still think that an inexistent "4XX+303 Found" code should be the correct. However, the "409 Conflict" is the best existing answer code (as pointed by @Wrikken), maybe including a Location header pointing to the existing resource.

8
votes

In your case you can use 409 Conflict

And if you want to check another HTTPs status codes from below list

1×× Informational

100 Continue
101 Switching Protocols
102 Processing

2×× Success

200 OK
201 Created
202 Accepted
203 Non-authoritative Information
204 No Content
205 Reset Content
206 Partial Content
207 Multi-Status
208 Already Reported
226 IM Used

3×× Redirection

300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
305 Use Proxy
307 Temporary Redirect
308 Permanent Redirect

4×× Client Error

400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Payload Too Large
414 Request-URI Too Long
415 Unsupported Media Type
416 Requested Range Not Satisfiable
417 Expectation Failed
418 I’m a teapot
421 Misdirected Request
422 Unprocessable Entity
423 Locked
424 Failed Dependency
426 Upgrade Required
428 Precondition Required
429 Too Many Requests
431 Request Header Fields Too Large
444 Connection Closed Without Response
451 Unavailable For Legal Reasons
499 Client Closed Request

5×× Server Error

500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported
506 Variant Also Negotiates
507 Insufficient Storage
508 Loop Detected
510 Not Extended
511 Network Authentication Required
599 Network Connect Timeout Error
7
votes

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).

4
votes

Another potential treatment is using PATCH after all. A PATCH is defined as something that changes the internal state and is not restricted to appending.

PATCH would solve the problem by allowing you to update already existing items. See: RFC 5789: PATCH

3
votes

More likely it is 400 Bad Request

6.5.1. 400 Bad Request


The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

As the request contains duplicate value(value that already exists), it can be perceived as a client error. Need to change the request before the next try.
By considering these facts we can conclude as HTTP STATUS 400 Bad Request.

2
votes

Stumbled upon this question while checking for correct code for duplicate record.

Pardon my ignorance but I don't understand why everyone is ignoring the code "300" which clearly says "multiple choice" or "Ambiguous"

In my opinion this would be the perfect code for building a non standard or a particular system for your own use. I could be wrong as well!

https://tools.ietf.org/html/rfc7231#section-6.4.1

1
votes

What about 208 - http://httpstatusdogs.com/208-already-reported ? Is that a option?

In my opinion, if the only thing is a repeat resource no error should be raised. After all, there is no error neither on the client or server sides.

1
votes

Why not a 202 Accepted? It's an OK request (200s), there were no client errors (400s), per se.

From 10 Status Code Definitions:

"202 Accepted. The request has been accepted for processing, but the processing has not been completed."

... because it didn't need to be completed, because it already existed. The client doesn't know it already existed, they didn't do anything wrong.

I'm leaning on throwing a 202, and returning similar content to what a GET /{resource}/{id} would have returned.

0
votes

I know it's been ages but I will leave an answer here which I see fit.

I think the best will be to use HTTP_306_RESERVED.

-2
votes

This is a user side fault and belongs to 4xx group. This is the right answer https://developers.rebrandly.com/docs/403-already-exists-errors