Overall:
Both PUT and POST can be used for creating.
You have to ask, "what are you performing the action upon?", to distinguish what you should be using. Let's assume you're designing an API for asking questions. If you want to use POST, then you would do that to a list of questions. If you want to use PUT, then you would do that to a particular question.
Great, both can be used, so which one should I use in my RESTful design:
You do not need to support both PUT and POST.
Which you use is up to you. But just remember to use the right one depending on what object you are referencing in the request.
Some considerations:
- Do you name the URL objects you create explicitly, or let the server decide? If you name them then use PUT. If you let the server decide then use POST.
- PUT is defined to assume idempotency, so if you PUT an object twice, it should have no additional effect. This is a nice property, so I would use PUT when possible. Just make sure that the PUT-idempotency actually is implemented correctly in the server.
- You can update or create a resource with PUT with the same object URL
- With POST you can have 2 requests coming in at the same time making modifications to a URL, and they may update different parts of the object.
An example:
I wrote the following as part of another answer on SO regarding this:
POST:
Used to modify and update a resource
POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/
Note that the following is an error:
POST /questions/<new_question> HTTP/1.1
Host: www.example.com/
If the URL is not yet created, you
should not be using POST to create it
while specifying the name. This should
result in a 'resource not found' error
because <new_question>
does not exist
yet. You should PUT the <new_question>
resource on the server first.
You could though do something like
this to create a resources using POST:
POST /questions HTTP/1.1
Host: www.example.com/
Note that in this case the resource
name is not specified, the new objects
URL path would be returned to you.
PUT:
Used to create a resource, or
overwrite it. While you specify the
resources new URL.
For a new resource:
PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/
To overwrite an existing resource:
PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/
Additionally, and a bit more concisely, RFC 7231 Section 4.3.4 PUT states (emphasis added),
4.3.4. PUT
The PUT method requests that the state of the target resource be
created
or replaced
with the state defined by the representation
enclosed in the request message payload.
Status 422 seems most appropiate based on the spec.
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. For example, this error condition may occur if an XML
request body contains well-formed (i.e., syntactically correct), but
semantically erroneous, XML instructions.
They state that malformed xml is an example of bad syntax (calling for a 400). A malformed query string seems analogous to this, so 400 doesn't seem appropriate for a well-formed query-string which is missing a param.
UPDATE @DavidV correctly points out that this spec is for WebDAV, not core HTTP. But some popular non-WebDAV APIs are using 422 anyway, for lack of a better status code (see this).
Best Answer
400 Bad Request would now seem to be the best HTTP/1.1 status code for your use case.
At the time of your question (and my original answer), RFC 7231 was not a thing; at which point I objected to
400 Bad Request
because RFC 2616 said (with emphasis mine):and the request you describe is syntactically valid JSON encased in syntactically valid HTTP, and thus the server has no issues with the syntax of the request.
However as pointed out by Lee Saferite in the comments, RFC 7231, which obsoletes RFC 2616, does not include that restriction:
However, prior to that re-wording (or if you want to quibble about RFC 7231 only being a proposed standard right now),
422 Unprocessable Entity
does not seem an incorrect HTTP status code for your use case, because as the introduction to RFC 4918 says:And the description of
422
says:(Note the reference to syntax; I suspect 7231 partly obsoletes 4918 too)
This sounds exactly like your situation, but just in case there was any doubt, it goes on to say:
(Replace "XML" with "JSON" and I think we can agree that's your situation)
Now, some will object that RFC 4918 is about "HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)" and that you (presumably) are doing nothing involving WebDAV so shouldn't use things from it.
Given the choice between using an error code in the original standard that explicitly doesn't cover the situation, and one from an extension that describes the situation exactly, I would choose the latter.
Furthermore, RFC 4918 Section 21.4 refers to the IANA Hypertext Transfer Protocol (HTTP) Status Code Registry, where 422 can be found.
I propose that it is totally reasonable for an HTTP client or server to use any status code from that registry, so long as they do so correctly.
But as of HTTP/1.1, RFC 7231 has traction, so just use
400 Bad Request
!