/** * Module dependencies. */ var debug = require('debug')('express:router:route'); var methods = require('methods'); var utils = require('../utils'); /** * Expose `Route`. */ module.exports = Route; /** * Initialize `Route` with the given `path`, * * @param {String} path * @api private */ function Route(path) { debug('new %s', path); this.path = path; this.stack = undefined; // route handlers for various http methods this.methods = {}; } /** * @return {Array} supported HTTP methods * @api private */ Route.prototype._options = function(){ return Object.keys(this.methods).map(function(method) { return method.toUpperCase(); }); }; /** * dispatch req, res into this route * * @api private */ Route.prototype.dispatch = function(req, res, done){ var self = this; var method = req.method.toLowerCase(); if (method === 'head' && !this.methods['head']) { method = 'get'; } req.route = self; // single middleware route case if (typeof this.stack === 'function') { this.stack(req, res, done); return; } var stack = self.stack; if (!stack) { return done(); } var idx = 0; (function next_layer(err) { if (err && err === 'route') { return done(); } var layer = stack[idx++]; if (!layer) { return done(err); } if (layer.method && layer.method !== method) { return next_layer(err); } var arity = layer.handle.length; if (err) { if (arity < 4) { return next_layer(err); } try { layer.handle(err, req, res, next_layer); } catch (err) { next_layer(err); } return; } if (arity > 3) { return next_layer(); } try { layer.handle(req, res, next_layer); } catch (err) { next_layer(err); } })(); }; /** * Add a handler for all HTTP verbs to this route. * * Behaves just like middleware and can respond or call `next` * to continue processing. * * You can use multiple `.all` call to add multiple handlers. * * function check_something(req, res, next){ * next(); * }; * * function validate_user(req, res, next){ * next(); * }; * * route * .all(validate_user) * .all(check_something) * .get(function(req, res, next){ * res.send('hello world'); * }); * * @param {function} handler * @return {Route} for chaining * @api public */ Route.prototype.all = function(){ var self = this; var callbacks = utils.flatten([].slice.call(arguments)); callbacks.forEach(function(fn) { if (typeof fn !== 'function') { var type = {}.toString.call(fn); var msg = 'Route.all() requires callback functions but got a ' + type; throw new Error(msg); } if (!self.stack) { self.stack = fn; } else if (typeof self.stack === 'function') { self.stack = [{ handle: self.stack }, { handle: fn }]; } else { self.stack.push({ handle: fn }); } }); return self; }; methods.forEach(function(method){ Route.prototype[method] = function(){ var self = this; var callbacks = utils.flatten([].slice.call(arguments)); callbacks.forEach(function(fn) { if (typeof fn !== 'function') { var type = {}.toString.call(fn); var msg = 'Route.' + method + '() requires callback functions but got a ' + type; throw new Error(msg); } debug('%s %s', method, self.path); if (!self.methods[method]) { self.methods[method] = true; } if (!self.stack) { self.stack = []; } else if (typeof self.stack === 'function') { self.stack = [{ handle: self.stack }]; } self.stack.push({ method: method, handle: fn }); }); return self; }; });