What's New in Edge Rails: Parameter Driven Response-Type Determination

Posted by ryan
at 9:02 AM on Thursday, June 01, 2006

The HTTP_ACCEPT header is used by web-clients to tell your application what type of response it wants and is the magic behind the very slick responds_to method of your controller. Rails edge now supports the case when you want to specify the type of response as a request parameter and not as an http header.

Currently, when a client sends an Http request to your app with an HTTP_ACCEPT header value of application/xml, you can do this in your controller to render the response as the appropriate XML:


# From example at:
# http://api.rubyonrails.com/classes/ActionController/MimeResponds/InstanceMethods.html#M000062
...
respond_to do |wants|
  wants.html
  wants.xml { render :xml => @people.to_xml }
end
...

Great, we’ve got an easy way to render the type of response the client has asked for without duplicating our controller logic. But, we don’t yet have a way to trigger this little bit of magic from anything other than the Http header – not a very friendly place to hang out. That’s what changeset 4384 addresses – the ability to determine the requested response type from a normal http parameter instead of the http header.

How it Works

Telling the request what response type you want is now as easy as adding a format parameter to your request and using the same respond_to determination as before. So this request sent from your web browser (which always sends an HTTP_ACCEPT header value of text/html or */*)


http://host/action?format=xml

Will override the supplied HTTP_ACCEPT header and will trigger the xml block of respond_to in your controller (imitating HTTP_ACCEPT = application/xml)

Overall a great way to programatically specify the response type without monkeying with http headers.

For further reading on the topic, here are some related posts:

tags: http headers, rubyonrails, rails

Comments

Leave a response

  1. Peter CooperMay 24, 2006 @ 07:27 AM
    I think I'd like to extend this so it can get it from the subdomain too. For example: http://www.yoursite.com/post/show/1 http://api.yoursite.com/post/show/1 The latter gets the XML, the former gets the HTML. Should be an easy thing to pull off though :)
  2. Jacob FugalMay 24, 2006 @ 07:27 AM
    @Peter: You could do something like that using your webserver (Apache or Lightty or whatever) config. Just have the server that handles api.yoursite.com requests proxy to www.yoursite.com with a modified HTTP_ACCEPT header. I'll admit that I don't know how to do that off the top of my head, but it should be possible...
  3. Ryan DaigleMay 24, 2006 @ 07:27 AM
    Peter, you could also do this with a pure Ruby implementation - I believe the enhanced routing plugin will let you form routing rules based on various parameters, one of them being subdomain. So...might this work for you?

    map.connect '/post/show', :controller => 'post', :action => 'show', :format => 'xml', :requirements => { :subdomain => 'api' }

    This keeps you from having to fiddle with HTTP header params, which just feels wrong, while also being a more portable solution as the config is contained solely within your Rails app.

  4. Peter CooperMay 25, 2006 @ 04:27 AM
    Excellent tips guys. I can see both working, although I imagine implementing it at the routing end might be more pure / platform agnostic.