route.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /**
  2. * Module dependencies.
  3. */
  4. var debug = require('debug')('express:router:route');
  5. var Layer = require('./layer');
  6. var methods = require('methods');
  7. var utils = require('../utils');
  8. /**
  9. * Expose `Route`.
  10. */
  11. module.exports = Route;
  12. /**
  13. * Initialize `Route` with the given `path`,
  14. *
  15. * @param {String} path
  16. * @api private
  17. */
  18. function Route(path) {
  19. debug('new %s', path);
  20. this.path = path;
  21. this.stack = [];
  22. // route handlers for various http methods
  23. this.methods = {};
  24. }
  25. /**
  26. * @api private
  27. */
  28. Route.prototype._handles_method = function _handles_method(method) {
  29. if (this.methods._all) {
  30. return true;
  31. }
  32. method = method.toLowerCase();
  33. if (method === 'head' && !this.methods['head']) {
  34. method = 'get';
  35. }
  36. return Boolean(this.methods[method]);
  37. };
  38. /**
  39. * @return {Array} supported HTTP methods
  40. * @api private
  41. */
  42. Route.prototype._options = function(){
  43. return Object.keys(this.methods).map(function(method) {
  44. return method.toUpperCase();
  45. });
  46. };
  47. /**
  48. * dispatch req, res into this route
  49. *
  50. * @api private
  51. */
  52. Route.prototype.dispatch = function(req, res, done){
  53. var idx = 0;
  54. var stack = this.stack;
  55. if (stack.length === 0) {
  56. return done();
  57. }
  58. var method = req.method.toLowerCase();
  59. if (method === 'head' && !this.methods['head']) {
  60. method = 'get';
  61. }
  62. req.route = this;
  63. next();
  64. function next(err) {
  65. if (err && err === 'route') {
  66. return done();
  67. }
  68. var layer = stack[idx++];
  69. if (!layer) {
  70. return done(err);
  71. }
  72. if (layer.method && layer.method !== method) {
  73. return next(err);
  74. }
  75. if (err) {
  76. layer.handle_error(err, req, res, next);
  77. } else {
  78. layer.handle_request(req, res, next);
  79. }
  80. }
  81. };
  82. /**
  83. * Add a handler for all HTTP verbs to this route.
  84. *
  85. * Behaves just like middleware and can respond or call `next`
  86. * to continue processing.
  87. *
  88. * You can use multiple `.all` call to add multiple handlers.
  89. *
  90. * function check_something(req, res, next){
  91. * next();
  92. * };
  93. *
  94. * function validate_user(req, res, next){
  95. * next();
  96. * };
  97. *
  98. * route
  99. * .all(validate_user)
  100. * .all(check_something)
  101. * .get(function(req, res, next){
  102. * res.send('hello world');
  103. * });
  104. *
  105. * @param {function} handler
  106. * @return {Route} for chaining
  107. * @api public
  108. */
  109. Route.prototype.all = function(){
  110. var callbacks = utils.flatten([].slice.call(arguments));
  111. callbacks.forEach(function(fn) {
  112. if (typeof fn !== 'function') {
  113. var type = {}.toString.call(fn);
  114. var msg = 'Route.all() requires callback functions but got a ' + type;
  115. throw new Error(msg);
  116. }
  117. var layer = Layer('/', {}, fn);
  118. layer.method = undefined;
  119. this.methods._all = true;
  120. this.stack.push(layer);
  121. }, this);
  122. return this;
  123. };
  124. methods.forEach(function(method){
  125. Route.prototype[method] = function(){
  126. var callbacks = utils.flatten([].slice.call(arguments));
  127. callbacks.forEach(function(fn) {
  128. if (typeof fn !== 'function') {
  129. var type = {}.toString.call(fn);
  130. var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
  131. throw new Error(msg);
  132. }
  133. debug('%s %s', method, this.path);
  134. var layer = Layer('/', {}, fn);
  135. layer.method = method;
  136. this.methods[method] = true;
  137. this.stack.push(layer);
  138. }, this);
  139. return this;
  140. };
  141. });