“Design depends largely on constraints.” — Charles Eames
Wednesday, 6 February 2008
Here’s one that I’ve been wondering about for a while, for the LazyWeb (HTTP Geek Edition);
PUTs and POSTs can result in the creation of new resources, or changes to the state of existing ones. The response to both can contain one of
Content-Location header, or204 No Content.Usually, a server will just choose which of these is most appropriate, and send it for all such requests. However, I can easily see cases where clients would want to hint to the server what they want back; e.g., a mobile client might prefer nothing, for efficiency, while a publisher might want to get a copy of the article they just submitted back, to make sure that they have any changes to the content locally.
My question is how a client should hint what they want back in such responses, and specifically whether this is purely an application-specific concern (and should therefore be expressed in the request-URI, for example), or is worthy of a standard (thereby better being expressed in a header).
BTW, I don’t think this is a form of content negotiation; that’s about the format of the response, and overloading it for this would produce some problems (e.g., how do you differentiate between an HTML status message and a HTML representation? There are also conflicts with probably resolutions of issue 69).
Filed under: HTTP, Protocol Design, Web, Web Services
I've run into this a few times. Esp. when the "clients" could be either browsers to other machines. Browsers might want a 302 after the POST, but machines might want 204. In many of the cases I ran into, the issue *seemed* to be tied to the mime-type, but not all.
maybe a "response-variant" header that suggests the preferred response code:
Response-Variant: 204
Wednesday, February 6 2008 at 1:42 AM +10:00
One possibility: http://tools.ietf.org/html/draft-snell-http-prefer-01
Wednesday, February 6 2008 at 1:55 AM +10:00
James beat me to it: the same discussion we had around the PATCH proposal and James-whip-out-drafts-like-crazy separated his prefer proposal in a separate spec.
Amusingly, "Snell" sounds like "schnell" in German which means quick/fast.
Wednesday, February 6 2008 at 2:03 AM +10:00
The "prefer" proposal is a great place to start. I also agree that there needs to be some generalized way to register new codes/extensions. Seems this can be handled loosely in the beginning, though.
Wednesday, February 6 2008 at 2:30 AM +10:00
Ah, I'd forgotten about Prefer. I think that would do the trick.
James, I notice that in 00 you had "content-returned" in the BNF, but not specified. Any reason you moved away from this in 01?
Also, "The Prefer mechanism is hop-by-hop" is a bit confusing, even with the explanatory text; it may be better to avoid the phrase "hop-by-hop" altogether there.
Thank you LazyWeb (and James :)
Wednesday, February 6 2008 at 2:32 AM +10:00
I removed the content-return largely because it was unspecified and needed to be clarified. Suggestions are definitely welcome on what preferences should be defined within the spec.
And, yeah, I agree about the hop-by-hop thing.
Wednesday, February 6 2008 at 2:36 AM +10:00
Cool. I think the resolution of i69 should help, and I imagine that content-return will need to talk about things like Content-Location and Vary (maybe not normatively, but at least to remind people).
Also, it would be good to talk a bit more about preference-extensions, perhaps laying out a registration policy for them (as well as an IANA registry). I suspect that they could be harmful if extended indiscriminately; because "preference" is such a vague concept, it can be overloaded easily (for good or not).
Wednesday, February 6 2008 at 2:43 AM +10:00
On preference extensions:
Seems like allowing the client to suggest an HTTP Status is a simple (and fully 'defined') extenstion pattern:Prefer: http-status=204
Prefer: http-status=302
Prefer: http-status=200 (vague but meant to mean return body)
Wednesday, February 6 2008 at 2:58 AM +10:00
Hey,
I don't get HOW this could be represented in URIs anyways? My understanding forces me to think that something like this needs to be done through headers. Could you please clarify that thought for me a little ?moving on, with regards to content-negotiation:
from the http rfc"
Most HTTP responses include an entity which contains information for
interpretation by a human user. Naturally, it is desirable to supply
the user with the "best available" entity corresponding to the
request.
"Thus, Content-negotiation doesn't necessarily imply format of the response. Again quoting ...
"
"content negotiation" --
the process of selecting the best representation for a given response
when there are multiple representations available.
"Representation for a given _response_ , not necessarily representation of a resource. Thus, for above example , there are two representations of the response :
1. with the content in the body of the message
2. with the body of the message empty , (or with links to the actual representation in it).
The fact that it was successful is stated in the response code.This comes under the purview of the definition of content-negotiation, if I understand it correctly. Infact, imho, putting a Prefer in the headers is just adding another help for server-driven content negotiation(like accept-*). Equivalently, right now, I guess a server can respond to a PUT/POST with a 300, which the client can decide whether to follow or not. This is again, content-negotiation.(agent-driven).
I might be way off, as I am a student right now ... so please kindly correct any mistakes I might have made.
Wednesday, February 6 2008 at 3:36 AM +10:00
Mike, I like that pattern better than the return-no-content, return-content approach I was originally taking.
Other than expected response status codes, what other kinds of preferences should be defined as part of the spec?
Wednesday, February 6 2008 at 4:28 AM +10:00
Another use case:
XHR currently follows the 302 (http://www.w3.org/TR/2006/WD-XMLHttpRequest-20060405/#dfn-send) which may or may not be a desirable outcome for a front-end application.
Could http-status: 200 provide a way to determine where the 302 would take you?
Wednesday, February 6 2008 at 4:57 AM +10:00
James:
Well, the http-status version scratches my itch[g].
The other extensions that come to mind involve altering the content that is returned (brief|summary|abstract|full) - seems a tricky item for intermediaries.
Mark, is this heading the direction you envisioned?
Wednesday, February 6 2008 at 5:10 AM +10:00
I'm not sure I do; people may use a wide-open mechanism like this in broken -- or worse, incompatible -- ways. Still interesting, though.
Wednesday, February 6 2008 at 5:13 AM +10:00
Mark:
I am guessing that your original post was about a "no-content|content" suggestion and nothing else, right? Were you at all thinking of cases where the server returns 302 and wether "prefer:" would address that?
Wednesday, February 6 2008 at 5:32 AM +10:00
Since the status of what happened can be addressed by existing status/headers, assuming that the server succeeded, the choice is between (a) give me a representation now, or (b) tell me where the updated representation is (in case a new resource is created). Agree that this is not content-negotiation, but is some form of response-negotiation.
Wednesday, February 6 2008 at 6:27 AM +10:00
Sounds to me like a prefect use case for an expectation-extension, such as "204-no-content" instead of "100-continue".
Wednesday, February 6 2008 at 4:07 PM +10:00
Robert:
Ha! Good point. Reading the spec on Expect header leads me to think this might result in lots of 417s from intermediaries, though.
Thursday, February 7 2008 at 1:47 AM +10:00
I was thinking of just 'no content' vs. 'status message' vs. 'representation'. 302 didn't come into it.
On the balance of things, I think I prefer using a string rather than a status code. While using status codes has a certain elegance/economy, my concern is that no matter how this mechanism is defined, people are going to try to leverage new things into it. I'd rather they do so in a string -- where the risk is confined -- rather than by inventing new status codes (which happens too much as it is).
All that said, it's not an incredibly strong argument, as we shouldn't spend too much time worrying about how things will get misused; they'll be misused anyway.
Using Expect isn't appropriate for the reason Mike mentions; it's strict, and hop-by-hop.
Thursday, February 7 2008 at 4:25 AM +10:00
Mark, yeah, I see your point. It's likely better that we set the bar higher and use iana registered string values rather than leave it wide open using the status codes. As an implementor, I like the elegance of the status code approach but it definitely is easier to abuse.
Thursday, February 7 2008 at 7:42 AM +10:00
I see the merit in iana-registered string values, too.
Am i correct to assume that this is something that would only be valid on PUT/POST, possibly DELETE? That means caching would not be affected.
Thursday, February 7 2008 at 4:25 PM +10:00
The Prefer header is defined generically for all HTTP methods, however, the server is given the option of ignoring the Prefer header completely. If the response to a request is affected by a stated preference, Vary: Prefer would need to be included in the response.
Friday, February 8 2008 at 7:45 AM +10:00
I'm kind of torn on the issue of using it with GET. James, I have a lot of sympathy for keeping these things generic and layered, but I can't think of any legitimate use of Prefer with GET, and certainly can think of abuses. Hmm.
Friday, February 8 2008 at 9:15 AM +10:00
Mark/James:
After my initial excitement about the notion of using http-status as a "Prefer" extension I started thinking about the implications for intermediaries and came to the same spot as Mark: using it for POST/PUT, possibly DELETE is pretty safe. but GET will be messy.
So, I'm down to the following possible responses:
no-body (returns 204 or 200)
body (returns 200 w/ body)
no-redirect (returns 204 or 200)
redirect (returns 3xx)There's some overlap, but I think that's OK.
I also think I might help to allow a list of values in order of preference:
no-redirect,no-body,body
Sunday, February 10 2008 at 2:24 AM +10:00
You said "a mobile client might prefer nothing, for efficiency."
In my AtomPub implementation, I just make the response body for a "201 Created" really small, so that it is likely to fit into the same packet as the headers. AtomPub requires me to return an Atom entry, but it doesn't have to be the exact entry that was created, so I return a minimal atom entry in response to POSTs: it contains just the atom:id, atom:updated, atom:author, atom:link[@rel='edit'|@rel='edit-media'], atom:title, and an atom:link[@rel='alternate'] that duplicates the atom:link[@rel='edit'] link. (This is basically what is in my collection feed as well.) Then, I compress it if there is an Accept-Encoding: deflate. The result is a response body that is basically indistinguishable, performance-wise, from no response for clients that are going to just ignore the response body. Additionally, if the client has an "Accept:" header that indicates that it prefers text/plain over application/atom+xml, then I can just return the IRI form of the URL in the Location: header in the request body (with "Content-Type: text/plain:charset=UTF-8").
That doesn't solve the problem where the client wants to get back a (full) representation of the resource. You said "A publisher might want to get a copy of the article they just submitted back, to make sure that they have any changes to the content locally." If it is likely that the resulting entry would be the same as the one that was PUT/POSTed, then it is wasteful to transmit the identical copy back to the client just so he can check that it is identical. Most of the use cases for "Prefer: no-content" would be better served with a conditional GET mechanism that says "send me back the new version of the resource if and only if it is different than the version I already have." "Prefer: no-content" is only useful when the client knows beforehand that the server doesn't alter submitted content, or when the client truly doesn't care about the final version of the resource.
A different mechanism would be better, like Reschke's "ETag on write" proposal: http://tools.ietf.org/html/draft-reschke-http-etag-on-write-08. Unfortunately, that proposal doesn't work well in the case where the server creates/updates multiple resources at once, and it doesn't work well at all with AtomPub media collections. I described the problem and a workaround for it at http://www.imc.org/atom-protocol/mail-archive/msg10712.html.
- Brian
Wednesday, February 13 2008 at 6:47 AM +10:00
Spec updated: http://www.ietf.org/internet-drafts/draft-snell-http-prefer-02.txt
Comments/suggestions are always welcome
Friday, February 15 2008 at 6:06 PM +10:00