Regex routing with Backbone.js

Routing is an application’s way of saying, “there would be something good at that URL, but since it’s hard to store things there I’ll just put it somewhere else and pretend you don’t notice.” It’s a hack, yes, but it’s also an easy system for turning abstract database identifiers into human-friendly URLs.

Most application frameworks have a single preferred format for their routing table that typically looks something like this:

$routes = array(
    'get /index'      => 'viewIndex',
    'get /single/:id' => 'viewSingle'
);

Backbone.js is no exception. By default, Backbone routes are limited to matching any slash-delimited URL fragment (“parameters”, denoted by a colon) and wildcard matches (“splats”, denoted by an asterisk). For the example above, the table in a Backbone router would be:

routes: {
    'index':      'viewIndex',
    'single/:id': 'viewSingle'
},

But what if you want to be more selective in your routing, and only route URL fragments that match a certain criteria? The obvious answer is to use a regular expression. Backbone supports this, indeed, all routes are converted into test-able RegExp objects as they’re added to the routing table. But Backbone’s Router.route method only supports adding such routes one at a time. That works fine as long as you only have a single route, or if you aren’t concerned about maintaining an exhaustive list of one-off routes–both rare cases for larger applications.

Fortunately, there’s an easy solution: set up an array of regular expression routes, then run Router.route on each route in the table.

Say you want to separate routes for lower-case names like “salmon”, “halibut”, or “sole” into those that belong with a specific letter. A few simple regex routes can handle this easily. Check it out:

var FishRouter = Backbone.Router.extend({

  // we'll define routes in a moment
  routes: {},

  // set up routing table
  initialize: function() {

    var router = this,
        routes = [
          [ /^fish\/([a-z] )$/,    'getUntastyFish', this.untastyFish  ],
          [ /^fish\/(s[a-z] )$/,   'getTastyFish',   this.tastyFish ],
          [ 'how-to-fish', 'getAllFish',     this.fishHowTo ]
        ];

    _.each(routes, function(route) {
      router.route.apply(router,route);
      // ^ Say it ten times fast
    });
  },

  // a handler for tasty fish
  tastyFish: function (name) {
    alert('Mmm...tasty '   name   '!');
  },

  // a handler for not-so-tasty fish
  untastyFish: function (name) {
    alert('That '   name   ' wasn\'t very tasty...');
  },

  // a handler for instructions
  fishHowTo: function () {
    alert('Choose a delicious fish from the list below.\n\n (hint: the tastiest fish start with \'s\')');
  }
});

// initialize the router
new FishRouter();

// call Backbone.history.start() to handle initial routing
Backbone.history.start();

Voila–a RegEx-enhanced routing table for Backbone.js. Call Backbone.History.start() and away you go!

Demonstration

Updated 03. Apr 2012 to reflect demonstration code

Hey, I'm RJ! For more learnings about software and management, find me @rjzaworski or sign up for my semi-regular newsletter.

Let’s keep in touch

Send me timely updates on software, product, and process.