Content-Type negotiation and REST (and how WCF fits in)

Just had a comment-exchange on my prior post on How to build a REST app in WCF. I thought I would reproduce and elaborate on it a bit here, in a post.

Kyle Beyer asked how to make WCF honor a content-type header (Accept header) in the request, and then modify the result of the REST request based on that header. At least that's what I think he's asking for.

My response is basically this - In REST, the URI dictates the result. Roy Fielding, the guy who coined the term REST in his doctoral thesis, says "all important resources must have URIs." I am no REST expert, but I am inclined to agree with Roy's view on this.

The issue of content-type negotiation within the realm of REST architectures is one that comes up often, but seems to me Fielding has been pretty consistent in saying that such negotiation is problematic and usually not very RESTful. The URI/URL itself maps to a response, including the content type of the response. In practice, you don't have a single URI that maps to a PDF file or an HTML file, depending on the Accept: header. You have two similar but distinct URIs, one for the PDF doc, and one for the HTML. The information within the two documents may be equivalent from a human perspective, but they are two distinct resources. That's the REST model.

If you have as a goal, is to have a single service that supports multiple content types from the same URL, I think that is not very RESTful. At the very least, whether and how REST systems should perform content-type negotiation is not at all settled. Not at all. It would be very presumptuous of Microsoft to embed into WCF and the .NET Franework in general, a model for content-type negotiation in REST exchanges, without first obtaining formal or informal consensus on the matter via some sort of standard or at least agreement on the REST discussion group. That would be a no-no! Not very polite.

This does not discount the validity of the desire - I can see why people would want to have this capability. What I am saying is that the REST approach, specified as it is today, does not encourage content-type negotiation. A reasonable conclusion to the premise that "All important resources must have URIs" is that content-type negotiation just isn't done.

In another spot, Fielding offers

We encourage resource owners to only use true content negotiation (without redirects) when the only difference between formats is mechanical in nature.

So I concede there is a gray area (or is it grey?). Let's look at a practical example: suppose your URI is https://server/Customer/18292 and you design your app so that if there is an Accept header that says "XML", the service delivers an XML doc of the customer data for the customer with ID 18292. That data might include name, address, and so on. If the content-type says "application/x-javascript" then the service delivers a JSON serialization with the same information. And finally if the Accept: header says image/jpeg, the service renders a photo of the customer.

It seems like the first option is allowable - XML to JSON is a mechanical transformation. But the third option (image/jpeg) seems to be outside the bounds of REST philosophy. That's not a mechanical transformation - it's a totally different resource.

Today, WCF doesn't handle the first, the acceptable approach. Today, when you use WCF to build a REST service, you specify the XML or JSON response type, not at runtime but in your application code, at compile time. It is possible to vary the content-type of the response to a WCF request. I'll work up an example of that soon. But the easy path within the WCF REST framework is to NOT do content-type negotiation. The easy part is to stuff the desired content-type in the URI itself. For example. https://server/Customer/18292/jpeg versus https://server/Customer/18292/record . If you think this is a huge issue with WCF, that is to say, you would like a single URI to return different content based on the Accept: header in the request, please let me know. As I said earlier, I don't think we (Microsoft) can unilaterally make decisions on how WCF ought to behave on that issue, but it would be good for us to hear your concerns. An additional option to you is to jump into that REST discussion group and hash this out with the community.

Cheers!