Don't Fear the URLs

rest mvc sinatra

Tue Aug 12 15:00:00 -0700 2008

I like models. They do the heavy lifting. They’re easy to spec. You can grab them at the console or from script/runner with ease.

I like views. There isn’t much to them - just an html document (or whatever) with some variables interspersed, and maybe a for loop here and there. Problems are easy to spot because views are so one-dimensional.

But controllers. Controllers, I’ve never liked. They offer a lot of infrastructure related to the request/response cycle which means they are clumsy to spec, and hard to access at the console. The prevailing view is to keep ‘em skinny, and for good reason: they suck to work with, so spend as little time writing code in them as you can.

But what if mapping web URLs onto controller objects is a case of object-oriented mentality taken too far?

Maybe that’s why I was looking to unify them with models. But here’s a better idea: get rid of the objects, and while we’re at it, unify controllers with routes.

Why is there separation between routes and controllers to begin with? Resource mapping is kinda cool, what with the helper urls. But building a url isn’t very hard. A good url scheme makes it easy, in fact.

Consider a simple RESTful action in Rails:

map.connect '/user/:id/authkey', :controller => 'user', :action => 'show_authkey', :conditions => { :method => :get }

class UserController < ApplicationController
  def show_authkey
    render :text => User.find(params[:id]).authkey
  end
end

Seems like a lot of code to indicate that /user/:id/authkey should display the contents of that user’s authkey code. What’s worse, the routes are in a separate file from the controller, so knowing what parameters come out of the url (just :id in this case) takes some digging.

Sinatra unifies routes and controllers. Let’s try that again:

get '/user/:id/authkey' do
  User.find(params[:id]).authkey
end

Ahhhh…much better.

Why hide urls behind a bunch of abstraction? I like urls, at least when they’re RESTful ones that are pretty to look at. They’re easy to parse for both humans and computers. They clearly state the types of resources that your service provides, and the relationship between them. Obfuscating them through routes, url-building helpers, and ActiveResource doesn’t provide much benefit that I can see.

Update
# GET /users/1
def show

Apparently even the Rails authors think that showing the URL is more understandable than the object/method-mapping.