IE doesn't let us REST

Posted by Jonathan

The reason why wrote up my rant about not getting too exited about REST is that I had some fun time paying for my blind usage of REST.

While developing Webistrano I thought that this would be a nice project for playing with all the RESTful stuff that Rails currently offers. So I started to map my resources and thereby only allowing certain HTTP verbs to certain URLs.

This all works nice until reality in the form of IE hunts you down.

Until recently all my Ajax calls used HTTP POST for getting updates from the server. I used POST for so long that I didn't remember why. In Webistrano I use Ajax to periodically get status updates on a running deployment. As getting status updates translates perfectly to HTTP GET on the resource I used this code for it:

# controller
def show
  @deployment = @stage.deployments.find(params[:id])

  respond_to do |format|
    format.html # show.rhtml
    format.xml  { render :xml => @deployment.to_xml }
    format.js { render :partial => 'status' }
  end
end

# view _status.rhtml
<% unless @deployment.completed? %>
  <script type="text/javascript">    
    function update_status(){
      new Ajax.Updater('status_info','<%=h project_stage_deployment_path(current_project, current_stage, @deployment) %>',{
        method: 'get',
        evalScripts: true
      });
    }
    
    setTimeout(update_status, 3000);
  </script>
<% end %>    

This worked nicely in Safari and Firefox but Internet Explorer would update the status-div with the whole page. So you got the page-in-a-page effect. I've spend several hours trying to debug from where IE was getting this strange output and why there were no requests to the server. And then I found the answer and remembered why in the past I always used HTTP POST for my Ajax calls.

IE was caching the GET Ajax call.

In order to prevent IE from caching Ajax calls your need to either supply different parameters on each request or switch to POST. Switching to POST is not so easy as Rails will not allow POST requests to the .../deployments/1 resource. So unique parameters on each request it is:

# view _status.rhtml
<% unless @deployment.completed? %>
  <script type="text/javascript">    
    function update_status(){
      new Ajax.Updater('status_info','<%=h project_stage_deployment_path(current_project, current_stage, @deployment) %>',{
        method: 'get',
        evalScripts: true,
        parameters: {
          random_differentiator: Math.floor(Math.random()*50000) // work around IE caching bug
        }
      });
    }
    
    setTimeout(update_status, 3000);
  </script>
<% end %>

The alternative would be to define a custom action on the deployment resource that would answer to a HTTP POST but this destroys the whole "one resource URL, different representations" REST thing.

So long for RESTful Web Applications with IE.

Don't get too RESTful

Posted by Jonathan

REST is a nice theoretical concept and Rails is pushing hard in this direction. We all heard about RESTful Rails and map.resources but at least in my surrounding its adoption is still lacking.

At the last Berlin Ruby User Group meeting somebody asked if one of us had a running RESTful application and only one out of 40 responded. Then we got into the whole 'what is REST, when is your application RESTful, and is the edit-view part of REST...' discussion.

Yes, it would be wonderful if the world would be full of REST Web Services instead of SOAP Web Services but in the end we are talking about Web Services. If your application does not expose a service, there is no need for hardcore REST. That's why nobody raised their hand, nobody had a service to expose. Not yet, you could argue. And by doing it the RESTful way they would prepare for the day that their application is so successful that they start to think about exposing some resources. In in this case they would be prepared. Just add some responds_to magic and boom, you got your Web Service.

And I answer YAGNI. Do it when you need it, too much preparation is evil.

At the moment some people (especially in the Rails community) see REST as the new Golden Hammer. Just hammer with it once or twice on your application and boom out comes a Web Service for virtually no effort at all. And this is what scares me. Don't get me wrong. I like the idea of REST and definitely prefer it to the WS-* way of doing things. But making your application a Web Service that will serve anything, from JSON to XHTML and XML, just because you can will not solve your problems. It will create new ones because you couple different views and interaction schemes.

Seeing DHH at the RailsConf Europe keynote hacking custom MIME types in order to render a different view for the iPhone didn't make me jump up and down in a jolly manner. It made me thinking if the Rails community pushed too hard to the RESTful side. The iPhone required it's own view because although running a stock Browser it has a different interaction scheme. A different interaction scheme should force you to have a different logic in the controller. The responds_to blocks start to grow in complexity and size.

This is the point where you should apply the idea of de-coupling, the idea of services. Let the iPhone have it's own Web Application. Let than this new application access the common resources that the Desktop Browser application and the iPhone application share. This access can be done through just loading the same models through svn:externals or through a REST Web Service.

The REST concept should de-couple different clients (controller and views) from each other and from and back-end code (models).

Sometimes the responds_to stuff makes sense. If you mostly expose data, then offering JSON and XML besides XHTML makes sense if by doing this you save your clients the transformation or expose the data to more clients that you could not reach before. But it you have a Web Application with a lot of interaction then coupling the Desktop Browser version with the iPhone version, the mobile version, the JSON version, and the XML version does not make any sense to me.

For me REST is about exposing interconnected resources through a unified interface. And yes you should let the client choose the representation. But different clients will handle and interact differently with the resources. So please think before reaching for your Golden Hammer.