WHOAHBOT!

JSONP web services with rack

Our story begins

Listen:

In our last gripping episode, we followed the grim tale of a cupcake and his deadly [coffee] messages.

These secret susurruses were fetched from a Rack app that can serve both JSON, and return a properly formatted JSONP for javascript clients.

Enter the hero: Rack

Rack is one of those things that you don’t get at first, and then you get it, and then you were embarassed that you didn’t get it in the first place. Or was that just me?

A Rack compatible ‘app’ just needs a few things to get going.

  • Define a call method
  • Return an array with three items
  • The response code
  • The headers
  • Anything that responds to the each method. Say… a string, or a pack of “wild dogs”.each do |bite| “ouch” end
  • It should be nice and return the proper headers, Content-type and Content-length

Install rack the same way you install any gemified rubies.

sudo gem install rack

Lambdas are a simple call girl, lets make her an app right now! We’ll return text/html as our mime type now so you can check it in a browser.

use Rack::ContentLength

app = lambda { |env| [200, { 'Content-Type' => 'text/html' }, "Hey there, sailor" ] }
run app

Put that little lady in a file called config.ru, and run ‘rackup ./config.ru’. You should be able to visit http://localhost:9292/ for a good time. What’s that ‘use’ statement for, you ask? Err… lets take a short break.

Intermission

Stumptowner

Your first rack app! As much as your first rails app ever returned with quite a bit less code. I was going to take a few more swings at rack jokes, the obvious ones just hanging there like rotten fruit, but I’m sure you’ll write an app to generate them for me anyway, so lets move on.

So, where we did put a string that salutes our fighting sailors, we could put nearly anything that responds to the each method. For the stumptowner app, we have a small, but quite silly string from the generator. The string that is returned is properly formatted JSON response.

Our poor sailor is on his own with lady lambda, so I’ve put my generator in it’s place.

app = lambda { |env| [200, { 'Content-Type' => 'application/json' }, Stumptowner.to_json ] }
run app

Great, fabulous, contragulations you graduate. Happy racking. Here’s your ruby shaped hat and diploma.

Wait, stop! Come back, cease and desist! This won’t do. Whoahbot, you’re fired. See d. trump for your haircut on the way out. This won’t work for javascript apps making cross-domain requests. We need a little p in our json for that.

Middleware

Yes yes, let us introduce you to rack middleware:


what’s great about rack
is that it will stack
on top of itself, hoo-ray!

Wierd, there’s no syntax highlighting for limerick. At any rate, middleware is the lego of web framework, it’s the layers in your cake, the stacks of waffles downstairs, complete with butter and maple syrups.

In our steamy ‘sailor come hither’ app above, we used the rack supplied Rack::ContentLength middleware to properly set the content-length header of our response. If you don’t do that, rack has a lint middleware that will wag it’s naughty finger at you. You can set the content-lengthby hand, or you could be lazy, the mark of any good programmer.

Saying ‘use Rack::Content::Length’ tells rack that before you return the finished response code, headers and body to the client, calculate the length of the response, and put that in the headers.

Just as there is a middleware for setting the content-length, the fabulous, handsome and prolific minds of the rack community have produced JSONP middleware as well.

The completed app sings the body electric like this:

require 'stumptowner.rb'
require 'jsonp.rb'

use Rack::JSONP
use Rack::ContentLength

app = lambda { |env| [200, { 'Content-Type' => 'application/json' }, Stumptowner.to_json ] }
run app

Tra-la! The beauty of this approach is that non JSONP clients just get regular JSON, while jQuery and his pals get what they need.

And they all lived happily ever after. The end.