The purpose of this POST is to PUT to REST the discussion on how to properly create resources on a server with good API design using HTTP and without violating REST architectural principles.
The problem this article addresses is the design of an HTTP + REST API which enables client systems to create resources on a server. Simplified with an example: a user has created a group message in an app on their mobile device and wants to share it. Other apps are not going to read the message from the client device (it may be unavailable and they won’t even know to look there) so the app wishes to transfer hosting responsibility for this resource to the server. The server needs an API which enables this functionality should be RESTFul and use HTTP as the transport.
The decision of whether to use PUT or POST to create a resource on a server with an HTTP + REST API is based on who owns the URL structure. Having the client know, or participate in defining, the URL struct is an unnecessary coupling akin to the undesirable couplings that arose from SOA. Escaping these types of couplings is the reason REST is so popular. Therefore, the proper method to use is POST. There are exceptions to this rule and they occur when the client wishes to retain control over the location structure of the resources it deploys. This is rare and likely means something else is wrong.
At this point some people will argue that if Restful-URLs are used, the client does knows the URL of the resource and therefore a PUT is acceptable. After all, this is why canonical, normalized, Ruby on Rails, Django URLs are important…. blah blah blah. Those people need to understand there is no such thing as a Restful-URL and that Roy Fielding himself states that:
A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations. [Failure here implies that clients are assuming a resource structure due to out-of band information, such as a domain-specific standard, which is the data-oriented equivalent to RPC’s functional coupling].
The idea of a “RESTful-URL” is actually a violation of REST as the server is in charge of the URL structure and should be free to decide how to use it to avoid coupling. If this confuses you see a future article on the significance of self discovering on API design.
As a side note, some may consider having the server instruct the client on how to create the URL. This is another edge case where the server might specify, via a resource, a URL for the client to PUT a resource. However, the server should have a valid answer if a GET is performed at that place before the client does a PUT there. Additionally, having the server generate, with foresight, all the locations for clients to PUT things is kludge so stop kicking and screaming about PUT and how the client can somehow know the location. You are being dragged to use POST and do it the right way (don’t worry, client libraries will make this easier when it catches on).
Using POST to create resources comes with a design consideration because POST is not idempotent (this scares people into using PUT to create resources when they should not). This means that repeating a POST several times does not guarantee the same behavior each time. This concern is demonstrated in the following situation:
- The client POST a new resource to the server.
- The server processes the request and sends a response.
- The client never receives the response.
- The server is unaware the client has not received the response.
- The client does not have a URL for the resource (therefore PUT is not an option) and repeats the POST.
- POST is not idempotent and the server …
Step 6 is where people commonly get confused about what to do. However, there is no reason to create a kludge to solve this issue. Instead, HTTP can be used as specified in RFC 2616 and, in my opinion, the server should reply with:
10.4.10 409 Conflict
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.
Replying with a status code of 409 Conflict makes a lot of sense as a generic response because: performing a POST of data which has an ID which matches a resource already in the system is “a conflict with the current state of the resource.”
Also, since the important part is for the client to understand the server has the resource and to take appropriate action. This is a “situation(s) where it is expected that the user might be able to resolve the conflict and resubmit the request.”
Finally, a response which contains the URL of the resource with the conflicting ID and the appropriate preconditions for the resource would provide “enough information for the user or user agent to fix the problem” which is the ideal case per RFC 2616.
Another option for the server might be:
10.3.4 303 See Other
The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource. The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.
The different URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).
Replying to a POST method with 303 See Other is actually discussed in section 9.5 where POST is defined in RFC 2616. However, the discussion is in regard to caching:
However, the 303 (See Other) response can be used to direct the user agent to retrieve a cacheable resource.
This cache specific language is my motivation for choosing 409 Conflict as the generic response in this situation. Take note that since idempotent and caching are often coupled, what RFC 2616 should say is that:
The 303 (See Other) response can be used to direct the user agent to an idempotent resource.
Therefore, 303 (See Other) is, in my opinion, a valid response but RFC 2616 will need updated (PUT method) for this the be standard behavior (though it does not, AFAIK, forbid using 303 here). The last option is:
10.3.1 300 Multiple Choices
The requested resource corresponds to any one of a set of representations, each with its own specific location, and agent- driven negotiation information (section 12) is being provided so that the user (or user agent) can select a preferred representation and redirect its request to that location.
Unless it was a HEAD request, the response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content- Type header field. Depending upon the format and the capabilities of the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection.
If the server has a preferred choice of representation, it SHOULD include the specific URI for that representation in the Location field; user agents MAY use the Location field value for automatic redirection. This response is cacheable unless indicated otherwise.
Replying to a POST method with 300 Multiple Choices is not a good candidate per the specification because this response is “cacheable unless indicated otherwise” which is in conflict with the POST method which is never cacheable. If one takes the option that a POST (along with required headers) indicates otherwise and decides 300 Multiple Choices is a valid response this could be used in cases where the server sees it most fit to accept the second POST and allow the client to select the correct version. Again though, the appropriate 409 (Conflict) response could handle this situation and adheres more closely to RFC 2616.
As a note, 304 (Not Modified) could not work because RFC 2616 specifies that it is only available for GET requests and it has no way of returning the URL for the resource.
To understand how the server knows there is a conflict, read my future article on “Resource IDs in Distributed Environments.” To understand the content which the server should reply with for the 201, 200/204, 409, 303, and 300 cases, see my future article on “An <a /> for the cloud.”