connectington

Trie-based URL and Method Routing for Node.js

npm install connectington
8 downloads in the last week
16 downloads in the last month

Connectington Build Status

Connectington is a trie-based URL and method router for Node.js based on routington. It was created out of frustration with Express' simplistic, method-first routing and can be used as a drop-in replacement. For more information on its motivations, read about The Imperfections of Express.

When should you use this?

  • Want your server to conform to HTTP specs
  • Want to decouple your app away from Connect/Express
  • Prefer a more modular routing framework
  • Prefer explicit routing
    • Wildcards are not supported
    • Only a single route will be matched, otherwise it will fall through
  • You repeat a lot of route definitions, ie looping through routes to add handlers
  • You want structure to your URL routes - routes are stored in a branch tree

Features

  • Supports the OPTIONS method automatically.
  • Supports 405 Method Not Allowed automatically.
  • Supports 501 Not Implemented automatically, assuming you use the middleware.
  • Allows you to "define" middleware stacks for easy re-use.
  • Faster (insignificantly) as it uses string matching instead of regular expression matching whenever possible.

API

Mounting to Connect/Express

var connectington = require('connectington')
var router = connectington()

To mount the middleware:

var app = express()
app.use(router.implementedMethods())
// static stuff
// cookie stuff
// session stuff
app.use(router.middleware())
// 404 handler
// error handler

Standalone

If you're not using Express or Connect, it will still work:

var implementedMethods = router.implementedMethods()
var middleware = router.middleware()

// ...
// Define routes
// ...

http.createServer().on('request', function (req, res) {
  implementedMethods(req, res, function (err) {
    if (err) {
      res.status = err.status
      res.end(err.message)
      return
    }

    middleware(function (req, res, next) {
      if (err) {
        res.status = err.status
        res.end(err.message)
        return
      }

      // If this point is reached,
      // no route has been matched
      res.status = 404
      res.end('Not Found')
    })
  })
})

Defining middleware

router.define('compress', connect.compress())
router.define('session', [
  connect.cookieParser(),
  connect.cookieSession()
])

You will define middleware stacks which will then be referrable by name. For example:

router.get('/', 'compress', 'session')

is equivalent to all of the following:

router.get('/', connect.compress(), connect.cookieParser(), connect.cookieSession())
router.get('/', connect.compress(), [
  connect.cookieParser(),
  connect.cookieSession()
])
router.get('/', [
  connect.compress()
  connect.cookieParser(),
  connect.cookieSession()
])

The idea is that you turn your middleware stacks into legos. You can define them early in your app, then re-use them throughout your routes without require()ing each of them. It will also make your routes much more readable as you can make it look like this:

router.get('/',
  'compress',
  'cache if visitor',
  'accept html only',
  'retrieve session',
  handler
)

function handler(req, res) {
  res.render('homepage')
}

Defining routes

For information on how the routing strings actually work, view routington's documentation.

There are two ways to create a route. The first is the usual Express way:

router.get('/things', 'compress', 'session', handler, ...)
router.post('/things', 'compress', 'session', handler, ...)
router.put('/things', 'compress', 'session', handler, ...)

The other is by defining a route, then adding stacks based on the method:

router.route('/things')
.get('compress', 'session', handler, ...)
.post('compress', 'session', handler, ...)
.put('compress', 'session', handler, ...)

In both versions, you can define multiple routes at the same time using an array:

router.route([
  '/things',
  '/thing/:id'
])
.get('compress', 'session', handler, ...)
.post('compress', 'session', handler, ...)
.put('compress', 'session', handler, ...)

Parameter matching

If you define a route like so:

router.get('/thing/:id', handler)

You can retrieve the value of id just like in Express:

function handler(req, res, next) {
  req.id = req.params.id
  next()
}

Accessing the trie

The trie, specifically the routington instance, is accessible at router.trie. You can manipulate it however you'd like. View it's documentation for more information.

Unsupported Express features

  • Wildcard routes are not supported. The purpose of this router is to make it easier for you to be explicit.
  • app.all is not supported. Simply define a stack and use it in every method.
  • Regular expressions are not supported as input arguments.

License

WTFPL

© Jonathan Ong 2013

me@jongleberry.com

@jongleberry

npm loves you