route.js 3.7 KB

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