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 http://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. http://server/Customer/18292/jpeg versus http://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!

Comments (14)

  1. Chuck says:

    Why not make it easy to do both and let developers decide what to do?

    I’m having a hard time justifying why I would use WCF for REST. It seems dead simple in ASP.NET (or any other web framework), yet obscure in WCF. There are two big problems I see, (1) Lack of good documentation and real examples for the Web Programming Model and (2) Why would I use an API that abstracts transport protocols for an architectural style built for a specific protocol?

    Number 2 is a big one for me. I understand the goal of WCF is to have a service accessible in various ways, yet RESTful services seem to have a very specific set of constraints. For example, if I’m using a ‘301 redirect’ as a response to a request, can I really make my service accessible via SOAP or any other transport protocol? Also, how do I write a ‘301 redirect’ in WCF (simple things should be simple…)?

    I’m going to keep trying to understand REST via WCF, but right now it seems harder than it should be.

  2. While I agree that content negotiation should not be abused, and a separate URI is preferable when in doubt, declaring content negotiation "unRESTful" seems like a cheap try to defend a shortcoming in WCF 🙂

  3. By the way, content-negotiation is one of the pillars of REST. Although providing different URIs for different representations is not  illegal, relying on HTTP 1.1’s agent-driven negotiation (via the Accept header) leaves you more flexibility and consistency.

  4. Berend de Boer says:

    The consensus in the REST community is that you quoted Roy incorrectly in the first instance. Also note that there is a difference between resource and representation. A REST system never returns resources, only representations, and that is where Content-Type negotiation comes into play and why it is important.

  5. DotNetInterop says:

    Hey Chuck – why do REST in WCF?  Because you want the extensibility and flexibility of WCF.  Listen if you need to do only REST, then WCF is probably not the right tool.  But if you need to do some REST, and some SOAP, and some heterogeneous system integration, and maybe some asynchronous connection., then WCF is probably a good tool.  If you like the "micro kernel" channel architecture of WCF with the extensibility capabilities (behaviors and so on), to do things like auditing, security checks, message transformation, streaming, and other things, then WCF might be the right REST tool for you.  If you would like the flexibility to choose your hosting mechanism, then WCF might be right for you .  

    If you are doing only REST, and only simple cases, then I agree, there are simpler frameworks to accomplish this.  WCF does a whole lot more.

  6. DotNetInterop says:

    Stefan, I am surprised at your reaction.

    I don’t believe I am trying to defend a shortcoming in WCF.  My intention was to say, content negotiation is an evolving area in the state of the art, and for WCF to take a clear path in advance of (rather than in concert with) a broader consensus would be an imprudent and perhaps not useful course of action for Microsoft to pursue.   Conversely, there is no incentive for Microsoft to obstruct the further evolution of useful "standards" (even if informal) around content negotiation and other similar areas.  

    In a space that requires interoperability, there is always an imperfect virtuous cycle of evolution of standards coupled with delivery of practical and usable technology from vendors.   Look at WSE as an example in this case.   Certainly , the more settled the standards are, the more effectively Microsoft will be able to support them.  

    And the large disclaimer I must add is this: I am not a regular visitor to the REST group on yahoo, nor do I have a regular dialog with REST thought leaders.  So I am no expert and it may be that content negotiation designs are much further along than I am aware, and that there is a consensus on how best to do it, that I am not aware of.  That is possible, and if it is the case, I apologize for my ignorance. Please do advise.

  7. DotNetInterop says:

    I’m glad to see the strong interest in the topic, and I’d encourage all of us to stay civil?  

    Berend, As for quoting Roy Fielding incorrectly, please do advise precisely what you mean.  I thought I was excerpting an email.  If I have done so incorrectly, or if I have misrepresented the context of the conversation, please do advise.

  8. Sorry, the quip about the WCF shortcoming was actually intended more as a tongue-in-cheek remark. Personally, I consider content negotiation a very valid and perfectly RESTful feature, and I would be surprised to hear Roy think different. So I think WCF should support it.

    On the other hand (or rather, the other side of the camp – namely, the Java one), the JSR 311 JAX-RS API expert group (which I’m part of) recently decided to adopt a default mapping of content types to extensions, essentially to enable doing content negotiation without doing HTTP content negotiation. The Rails framework does something similar. So ideally, I believe both having separate URIs as well as separate representation types are valid strategies, and any framework should enable the developer to choose.

  9. Chuck, in a comment on a previous post , posed this question: Why choose WCF for a REST app? Here it

  10. Kyle Beyer says:

    Hi Dino,

    Thanks for you thoughtful writeup on this.  I think it’s great that you are making an effort to ensure that Microsoft build WCF to enable development of RESTful APIs.

    I’m not a REST purist.  So, I’m not as interested in whether content type negotiation makes a service un-RESTful as I am in making sure a service is both useful and easy to communicate with.

    As a consumer of services, getting back the content type that is requested makes a lot of sense.  As a service provider, being able to develop a single set of services that can dynamically return a resource in the requested content type makes a lot of sense.

    As it stands, it seems quite difficult to for developers to create services with this functionality in WCF.  I think it would be a useful feature in WCF to have ‘Auto’ in addition to XML & JSON as options for the RequestFormat and ResponseFormat attributes.

    Thanks,

    Kyle

  11. DotNetInterop says:

    Hey Kyle, I completely understand what you are saying, and I think your scenario is a good one to cover. I agree with you that it would be nice for WCF to better support varying Content-Type with minimal code hassle.  The WebMessageFormat.Auto seems like a really good idea.  Definitely worth exploring.

    Maybe check out my followup post on this. 

     

  12. If you want to be accurate, your json / xml representation is an IR, your URI is a resource. Using content type negociation in the realm of httpRange-14, a resolution of the w3c, would mean that upon requesting the uri you would return a 303 with the location in the format you requested.

    Transparent conneg still has value, so does returning 300 when conneg fails and several representations exist.

    The reality is that WCF completely missed the boat on the whole architecture of conneg and to a certain extent REST itself. The astoria guys gave it more of a thought, but even there the system is not transparent enough (difficult to plug-in your own resource content type). Part of REST should be not to rely on generic formats like application/xml or application/json, but to rely on specific mime types for what you need: An existing format or an application/vnd.mycompany.resourcetype+xml for example.

    If you create a new format and a new schema, you may as well create a new mime type.

  13. Nick Williams says:

    Shakespeare’s sonnets can be found in braille, english, spanish, and a multitude of other languages.  These are all the same resource, just different representations of it.  The same applies with content negotiation – it is only a mechanism to negotiate how the resource is represented.  They are not different resources.

  14. Mike O'Brien says:

    The WCF REST Contrib library enables this functionality:

    http://wcfrestcontrib.codeplex.com/

    It also includes a POX formatter and form url encoded formatter and allows you to easily create your own. Formatters are mapped to mime types and automatically selected to serialize/deserialize the entity body based on the content type and accept headers.

    m