Erik Hetzner wrote:
The point is, the state AFTER each request is processed is the same,
but the status code is different. You have argued, w.r.t. DELETE, that
as long as we have the same resource state after the request is
processed, we must have the same response, whatever the previous state
of the resource was (that is, either existing or not existing). But
this is not in the HTTP spec, it is not a principle of REST, and it
has nothing to do with idempotence.

I believe it is a principle of REST as applied to HTTP. Of course, my last name is not Fielding, so what do I know.

I'm not exactly following what you're saying about "AFTER each request". Again, here's how I look at it, with two examples; your PUT example and a caching example.

First, let's establish what a "request" is: url + pre-condition headers + HTTP method + message body (some methods requiring a message body (like POST, PUT) and others not (like GET or DELETE)).

Here's the caching example:

Step 1) A client requests a resource via GET. It has not previously requested this resource, so it has no ability to include a If-Modified-Since or If-None-Match precondition header.

--- Client -------------------
GET /some/url HTTP/1.1
Host: foo

--- Server -------------------
HTTP/1.1 200 OK
Etag: "abcdefg"

message body


A 200 OK is returned, along with a new Last-Modified and/or Etag header. For simplicity, we'll just use the ETag, which the client records along with the cached version of the resource.

Step 2) A client makes a request for the _same_ resource using the _same_ url. However, this time the client uses a If-None-Match precondition in the request. Thus, the "request" itself (as defined above) is different.

--- Client -------------------
GET /some/url HTTP/1.1
Host: foo
If-None-Match: "abcdefg"


--- Server -------------------
HTTP/1.1 304 Not Modified


The server replies with a 304 Not Modified reply. The server can return a different status code because the request is different. It will always return this 304 Not Modified reply until the resource changes (for that specific request). It will always return a 200 if the precondition header is not included. The server is unable to escape these rules.

The point is, notice that the Request has changed. It doesn't matter how many times you throw the first request at the server, it will always return 200. Likewise, the second request will always return 304, until the resource's state changes.

This exact same evaluation can be applied to your PUT example, except of course the server replies with Precondition Failed (which according to the spec is an appropriate response for a PUT method under the circumstance you describe). It will always return 412 after the first PUT for identical requests (because the first request modifies the resource, and thus allows the server to return a different status code for the same request).

That's the core of my argument: A status code should always be the same for an identical request so long as the resource has not change.

If the server is coded to return a different status code for an identical request when the resource state has not changed, then that is wrong. The only liberty a server has to return a different status code for the same request is when the resource has changed.


A logical conclusion of this principle would be that PUT should never
return a 201 Created, because this depends on what the state of the
resource was before the request was received. PUT should always return
200, because the state of the resource previous to the request is
irrelevant.

You're right. PUT should never return 201 Created. The reason? 201 Created should have a Location: header sent in reply. The client doesn't need a Location: header, since it already knows the location the resource.

The client doesn't care whether the resource was _newly_ created, or just _updated_. What does the client care? This goes back to the same argument about DELETE. So long as the state change for the resource occurred, that's all the client cares about, not whether it's newly created or not. What is newly created anyway? And, what does the client care to know the difference?

The 201 Created status code is only useful when the resource's URL is not known by the client. Therefore, 201 Created is only applicable to the POST method, because POST doesn't know what the url is for the resource in its message body.

A successful PUT can return 204 No Content for an immediately successful state change, or 202 Accepted for one that will occur in the future. There are no other 2xx response codes appropriate for a PUT operation.

Again, this is not arguing HTTP spec, as the HTTP spec is quite a bit more lenient than the rules I've suggested. And, the rules I've suggested may not strictly be REST rules, as I believe Fielding was describing REST as an architectural pattern that is applicable to protocols other than just HTTP.

However, if you follow the HTTP spec and you apply the REST principles to it, I believe what you end up with is this logical mapping of what HTTP status codes can be returned for which HTTP methods. For 2xx only, it goes:

GET => 200, 206
PUT => 204, 202
POST => 201, 202, 205
DELETE => 204

HTML is an abomination to the HTTP spec. So, I'm not arguing what is in current use, more what it ideally should be.

No more replies from me. I feel I've hijacked the thread, and we're obviously way off RESTlet discussion. ;)

Adam

Reply via email to