JSON-P Rack Handler 1
Updated 2008-06-19 – better support Halcyon
JSON-P Rack Handler
Juicing Ruby
I’ve been trying to find ways to squeeze all the juice out of Ruby lately. So many blog posts talk about how Rails doesn’t scale, Ruby is slow, blah blah. I had a convo with another developer at work today that went something like this:
Me: if we’re willing to do anything for performance we’d we just switch to Java
Jared: Yeah let’s not do that.
Switching to Java would be a big trade off in performance but also in development time. That’s a big trade off that none of us around here think is worth. That’s where this Rack handler comes in.
JSON-P Caching
I’ve posted before about how to use JSON-P in Rails and how to cache JSON-P in Rails with fairly decent results (500+ reqs/sec) but I felt like I could do better. Action caching always seemed like the best way to cache the full JSON output of a request but the fact that jQuery uses a dynamic callback takes action caching out of the equation.
Speeding up JSON-P
500+ reqs/sec is good and all but I felt like if I could action cache then somehow pad that cached JSON result with the callback I’d get better performance. I thought I’d see what Merb could offer on the JSON-P front. In my quest to juice Ruby my test setup looks like this: Merb, Datamapper, Memcached (the c gem), Memcached (the server) and Ebb. I’m really impressed with Merb and Datamapper in terms of development and I’m equally impressed with Rack and Ebb for performance.
I read recently it’s possible to use Rack to filter results to gzip output, which got me thinking. Why not try to do the same to pad my action cached JSON. Well it is possible and I’m squeezing out JSON-P at ~1200 reqs/sec with the JSON-P Rack Handler with my test stack.
JSON-P Rack Handler
# config/jsonp.rb
class JsonP
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
request = Rack::Request.new(env)
response = pad(request.params.delete('callback'), response) if request.params.include?('callback')
[status, headers, response]
end
def pad(callback, response, body = "")
response.each{ |s| body << s }
"#{callback}(#{body})"
end
end
Config
# config/rack.rb
require 'config/jsonp'
use JsonP
run Merb::Rack::Application.new
In Halcyon
# runner.ru
...
require 'config/jsonp.halcyon'
use JsonP
run Halcyon::Runner.new
Rails Support Soon
One last thing… whenever Rails starts using Rack, you’ll be able to use this in your Rails app.
About Me: I’m a developer with Sports Technologies, a Rails firm specializing in community focused web applications aimed at sports and entertainment. We’re always looking for Rails talent, if you’re looking to work on rewarding high profile projects with a seasoned team of professionals give us a shout.
JSON-P on Rails with JQuery
JSON-P based Comment
Over the last several months I’ve had the pleasure of developer JSON based commenting solutions for publishers. I couldn’t be happier using JSON as a transfer method for moving ActiveRecord based object from the database almost directly to the consumer. I’ve run into some difficulties here and there mainly due to the Same Origin Policy which is a bastard of a browser rule that makes sending JSON across domains difficult. Even though prototype.js seems to support sending requests across domains there is no native script transport in prototype and worse yet it appear some browsers won’t allow AJAX across subdomains to overcome the SOP rules. I searched all over the web and found a few hacks for adding the script tag to prototype.js but I found the best solution was built native into JQuery’s getJSON. I was really taken with JQuery’s ability to handle the script transport method out of the box but I think even more I’m taken with JQuery’s syntax. I had a conversation with Less Everything’s Steven Bristol about 6 months ago and he asked if I had checked out JQuery. I had briefly looked at it but I wasn’t wowed by it (probably because I didn’t use it on a project). Steven: “isn’t it the best thing you’ve ever seen?” Me: It’s ok. (*my answer to everything – ask my wife). Six months later I get to use it on a project and my answer to you Steven is YES it is the greatest.JSON-P
Back to the subject… So the problem is that a browser doesn’t want to send a request across domains for fear that your secret info will be compromised by some would be hacker. The solution JSON padded with a callback method combined with a plain old script tag aka JSON-P. With JQuery the idea is that you can pass a URL into JQuery’s getJSON method with a ? for JQuery to bind it’s on changing function name that handles a callback. Sound like a hack? Yes but everyone is doing it. I’ve seen some skeptics but overall this is an accepted solution. And until JSONRequest is accepted as a safe cross site transport JSON-P is here to stay.Does Rails support JSON-P?
Bet your ass it does. Right out of the box Rails supports the callback option to be passed in on a :json render. Like so:
render :json => @comments, :callback => params[:callback]
