GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS

Written by thoughtbot

Video: Sinatra At Boston.rb, Part 2

This is the second in a series of short videos. They feature Blake Mizerany discussing Sinatra and Heroku in great technical detail at September’s Boston.rb. Watch Part 1.

In HD this time… watch out, the kid is learning!

"use" is built-in

In this video, Blake extends his example code using Rack middleware from rack-contrib called Rack::AcceptFormat:

Adds a format extension at the end of the URI when there is none, corresponding to the mime-type given in the Accept HTTP header.

Example from the docs:

GET /some/resource HTTP/1.1
Accept: application/json

GET /some/resource.json HTTP/1.1
Accept: application/json

Blake says we can use Rack::AcceptFormat in our config.ru or in Sinatra, depending on the situation.

This middleware will re-write path_info

What's cool about this is Sinatra doesn't have to know about Rack::AcceptFormat's deeds making our work with content types easier. By the time the request gets to Sinatra, ".json" has been added. Call it "just-in-time routing".

Rack Hoptoad

On the day Blake spoke at Boston.rb, he and I sat down to get Rack Hoptoad working on Heroku. Staying true to the philosophy of backing into patterns, we started with a bare-bones Rack app, then moved to Sinatra.

In both cases, we need to specify the gem in our .gems file:

# http://docs.heroku.com/gems#overview
rack_hoptoad

Rack:

# config.ru
require 'rack_hoptoad'

use Rack::HoptoadNotifier, "123abc"
run lambda { |env| fail "Fail!" }

Sinatra:

# config.ru
require 'rack_hoptoad'
require 'example'

use Rack::HoptoadNotifier, "1234"
run Sinatra::Application

# example.rb
require 'sinatra'

configure :production do
  enable :raise_errors
end

get '/boom' do
  fail "Fail from Sinatra!"
end

When Rack, when Sinatra?

Blake's rule of thumb is to start with Rack when he knows, when he's starting, that he's only going to have one route, maybe two, and there's nothing special about them.

In many ways, Sinatra is just a clean DSL around HTTP with lots of delegation to Rack. Without it, you'd have messy conditional statements that are fine for a couple of routes, but get out of hand beyond that.

Routing tricks

Access wildcard operators using block syntax instead of a Rails-style params[:first_name]:

get '/:first_name/:last_name' do |first, last|
  "Hello, #{first} #{last}"
end

Sinatra allows splats, such as this non-greedy match:

get '/:name.*?/:last' do
end

The returned object will be a normal Ruby MatchData object, so everything you can do with that applies in your Sinatra code.

next

Stay tuned next time when our protagonist discusses:

  • POSTing data to a legacy API
  • war stories
  • view templates