tags:

views:

116

answers:

5

My colleagues and I are implementing a number of RESTful HTTP services, and we're trying to make sure we are a) following the spec, and b) doing the "right" thing where the spec is short of detail.

Here is a particular situation that we have come to and are looking for opinions from the community on:

Suppose you have a resource /People/Bob, and your client is going to update it with a PUT. The server can produce representations for /People/Bob in application/json and text/html. The server can interpret representations for /People/Bob in application/json.

Given this request:

PUT /People/Bob
Content-Type: application/json
Accept: application/xml

{ name: "Still Bob" }

The server can't produce an XML representation, but it can process the incoming JSON. So we know the correct answer is for the server to return status 406.

The question is: should the server have performed the update to /People/Bob?

+2  A: 

+1 for Philosophy of REST.

Without detailed knowledge of the HTTP spec, I would simply choose one of the options and document the quandary and the choice.

My preference would be that the server cannot respond as requested, then it should not process any of the request at all.

But that may not work in some scenarios, so you might have to do the opposite.

Justice
Hehe, thanks. We are very dead-set on having the truthiest implementations of REST around.I'm leaning in this direction (bail the whole request), and the main thing holding me back is that it will require a re-write of one section of our engine hehehehe
Chris Guidry
Thanks to everyone who responded. I believe we going to go with failing the whole request, if I would just stop being so lazy.
Chris Guidry
+1  A: 

I would argue 'yes' in theory, but 'no' for real-world application.

I see the logic in not processing if there's an error. Since you return a 406, not a 500, I would know that it's not an error in the data I provided, but rather in the way the result is being presented to me.

That said, some applications won't check for error codes; they will just see that it came back with an error rather than the XML it asked for, and assume the transaction failed.

I assume your not handling application/xml is not an actual problem, but for the purposes of the question - if this is actually being deployed as a real-world service, you'd almost certainly want to be able to have an XML representation, as that's (I suspect) the most common RESTful interaction, and many callers would probably be hard-coded to use XML.

To sum up: if you actually aren't providing application/xml, then I would say, don't perform the update. If you're handling all the standards, but you're planning for the contingency where a user will ask for application/fooSomethingNonStandard, then go ahead and perform the update, but be sure you respond with a 406.

Matt Poush
Thanks for the feedback. The question isn't really about XML or any particular format. We're trying to decide if the engine that chooses our representations should inspect the Accept type before or after processing the request. Doing it at the end of the request (which we do now) means answer 'yes'; doing it at the beginning of the request means answering 'no'.
Chris Guidry
+1  A: 

The question is: should the server have performed the update to /People/Bob?

From the HTTP spec, a 406 means:

The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.

Unless it was a HEAD request, the response SHOULD include an entity containing a list of available entity 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.

   Note: HTTP/1.1 servers are allowed to return responses which are
  not acceptable according to the accept headers sent in the
  request. In some cases, this may even be preferable to sending a
  406 response. User agents are encouraged to inspect the headers of
  an incoming response to determine if it is acceptable.

If the response could be unacceptable, a user agent SHOULD temporarily stop receipt of more data and query the user for a decision on further actions.

That note in the middle about HTTP/1.1 may be your answer. I read it as saying "you may return a 200 in response to the PUT request to /People/Bob when the user agent specifies application/xml in the Accept header, selecting any suitable content-type, and that this outcome may be preferable to returning 406."

Under this scenario, the PUT would succeed on the server, return a 200, but the client would get an application/json representation. The client needs to be able to handle that possibility by making sure that it understands the media type given in the Content-type header, and behaving in a well-defined manner if it doesn't.

But this is always true anyway.

One more thing: you may want to consider not using plain-vanilla media types like application/xml and application/json, but instead define your own custom media types, maybe based on XHTML or JSON. All of the client-server coupling in a RESTful application happens through media types. Without media types rich enough to capture your domain concepts, you're incompletely specifying your REST API.

Rich Apodaca
Thanks, very astute observations. I'm tempted to go with this answer (it's what one of my colleagues suggested off the bat), but I don't feel right about sending back something useless to the client.Also, thanks for the advice on media types, but the ones I chose for this example were just vanilla and would apply to any combination of media types.
Chris Guidry
This is starting to sound like the kind of coupling between client and server that's best avoided. How feasible would it be to either equip the server with XML output or equip the client with JSON input? If the answer is "not very", then how about returning a 400 to indicate unambiguously that the request failed and the server was not updated?
Rich Apodaca
+1  A: 

One way out of your conundrum is to have a successful PUT return a 204 (No Content). That way the client's Accept header is irrelevant to the issue of whether the update is performed.

A "RESTful" (or at least "HTTP-embracing") client will know not to update its current "page", and that it will have to do a GET in order to refresh its view of the just-PUT resource. The Accept header on that GET is now, of course, a separate concern from the update atomicity.

system PAUSE
Thanks for the feedback, but in our architecture, we allow PUT to have a response body, which is the most efficient way to communicate server-side changes, validation updates, and validation messages to the client (including a body on 422, which we use for validation failures).
Chris Guidry
@Chris, I kinda figured you were too far along. :) And definitely understand wanting to avoid an extra request-response. Just figured this answer might be useful to others who face a similar question, and who might have different requirements.
system PAUSE
A: 

I would either succeed and return a 200 using the method Rich suggests above or a 406 and fail. The protocol does not allow for a more nuanced approach mixing 2xx (Success) with 4xx (Error) codes so 4xx can be read to imply NOT Success.

Stephen Petschulat