Publicidad:
Terra
La Coctelera

un rato de sol

i will work harder, ja ja ja, no ahora en serio.

4 Julio 2009

RESTful JSONP in Rails using Rack middleware

Rails 2.3 has finally included support for Rack. The Rack project (http://rack.rubyforge.org/) consists of an abstraction layer on top of the webserver that provides a common set of services for developers while hiding the complexity of the web server software whatever it should be (mongrel, glassfish, thin, etc).

The support for Rack is a major accomplishment of the Rail Core Team and opens a lot of interesting new capabilities for the framework users.

In this post entry I will comment a possible use of Rack to provide support for RESTful-like requests for JSONP in Rails.

As you surely know, current desktop browsers only give support for GET and POST HTTP requests. This is a serious difficulty for clients trying to follow REST design guidelines in browser clients, since PUT and DELETE methods are needed to carry request to the server asking for the update and deletion of a resource.

Rails address this problem allowing to pass a '_method' parameter in POST requests that overwrites with its value the POST method of the request. In this way, PUT and DELETE requests can be sent from a HTML form or from an AJAX request.

But this feature only solves half of the problem. Web browsers implement a security model known as the Same Origin Policy (http://en.wikipedia.org/wiki/Same_origin_policy), where only requests to the same domain of the current URL are allowed. This policy effectively forbids cross domain AJAX requests. At least until a common specification for cross domain XMLHTTPRequests can be agreeded and implemented (http://dev.w3.org/2006/webapi/XMLHttpRequest-2/).

One work-around for this problem has been found in the use of JSONP (http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/) a technique where a new SCRIPT tag is inserted into the web page DOM with a callback parameter. The server answers with a script where the callback parameter value is used as a function name that is invoked with the data from the server passed as the actual parameter invokation value.

JSONP, though nothing more than a hack, is been used by many web pages and services to provide data to javascript clients and mashups. A big problem with JSONP appears when you try to use JSONP in a RESTful way. Including the SCRIPT tag in the page initiates a new GET request to the server, so if you wants to use JSONP to send a request for creating a new resource (POST), updating it (PUT), or deleting it (DELETE), you must use some work-around like the use of the _method parameter in Rails. But the overwriting of the HTTP method in Rails only works with POST request: no RESTful JSONP for you my friend.

Of course, you can always try to modify the behaviour of the method override mechanism of Rails with a little bit of monkey patching. Solutions in these direction has been proposed (http://www.actsasflinn.com/2008/06/13/cross-domain-restful-json-p-with-rails) but they are very likely to break with each new Rails release.

With the support for Rack in Rails 2.3 the situation has changed and a cleaner way to change the behavior of MethodOverride in Rails can be built.

Now, MethodOverride is a class of the Rack Rails middleware stack (http://rack.rubyforge.org/doc/classes/Rack/MethodOverride.html). Rack Rails allow developers to insert new middleware classes in the stack (http://guides.rubyonrails.org/rails_on_rack.html), so you can easily add a new middleware before MethodOverride that allows the use of _method parameters with GET requests, without the need of monkey patching:

 module SemanticResource
   
   # Allows overwriting of HTTP method also in
   # GET HTTP requests in order to allow
   # RESTful JSONP calls
   class RestfulJsonpMiddleware
   
     HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS)
     METHOD_OVERRIDE_PARAM_KEY = "_method".freeze
     HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze
     
     attr_accessor :method_parameter_name
     
     def initialize(app)
       @app = app
       @method_parameter_name = METHOD_OVERRIDE_PARAM_KEY
     end
 
     # We check if the method parameter is in the request
     # and set up the request to allow the execution of the
     # overwritten HTTP method
     def call(env)
       req = ActionController::Request.new(env)
       method = req.params[@method_parameter_name]
       method = method.to_s.upcase
       if HTTP_METHODS.include?(method)
         env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"]
         env["REQUEST_METHOD"] = "POST"
         env[HTTP_METHOD_OVERRIDE_HEADER] = method
       end
      @app.call(env)
     end
   end
 end
 

And now we can add the middleware in config.rb

 config.middleware.insert_before(Rack::MethodOverride,SemanticResource::RestfulJsonpMiddleware)

That's it, cross domain RESTful AJAX for Rails in a little bit cleaner way! You must take some time to consider the security implications of this change in your application though.

servido por Antonio 2 comentarios compártelo

2 comentarios · Escribe aquí tu comentario

xcvb

xcvb dijo

Jagadguru Ramanujacharya cheapest wow gold.These days, fast cash shanghai massageloans are possible to get online

18 Diciembre 2009 | 05:05 AM

dsafd

dsafd dijo

come !come my dear friends .come here buy fake rolex .cheap fake rolex at here .heave the replica rolex

3 Enero 2010 | 01:00 PM

Escribe tu comentario


Sobre mí

Avatar de Antonio

un rato de sol

Barcelona/Salamanca, España
ver perfil »
contacto »
Trabajador del metal y del acero, en la gloriosa XING AG, escribo software con el que poder ganarme el jornal. En mi tiempo libre sigo tecleando código de bonitos colores a medio camino entre lo sublime y lo terrible. Últimamente me gustan mucho los gatos.

Fotos

Antonio Garrote Hernández todavía no ha subido ninguna foto.

¡Anímale a hacerlo!

Buscar

suscríbete

Selecciona el agregador que utilices para suscribirte a este blog (también puedes obtener la URL de los feeds):

¿Qué es esto?

Crea tu blog gratis en La Coctelera