thoughts/node_modules/express/lib/router/route.js
node_modules/express/lib/router/route.jsRaw
1/*!
2 * express
3 * Copyright(c) 2009-2013 TJ Holowaychuk
4 * Copyright(c) 2013 Roman Shtylman
5 * Copyright(c) 2014-2015 Douglas Christopher Wilson
6 * MIT Licensed
7 */
8
9'use strict';
10
11/**
12 * Module dependencies.
13 * @private
14 */
15
16var debug = require('debug')('express:router:route');
17var flatten = require('array-flatten');
18var Layer = require('./layer');
19var methods = require('methods');
20
21/**
22 * Module variables.
23 * @private
24 */
25
26var slice = Array.prototype.slice;
27var toString = Object.prototype.toString;
28
29/**
30 * Module exports.
31 * @public
32 */
33
34module.exports = Route;
35
36/**
37 * Initialize `Route` with the given `path`,
38 *
39 * @param {String} path
40 * @public
41 */
42
43function Route(path) {
44 this.path = path;
45 this.stack = [];
46
47 debug('new %s', path);
48
49 // route handlers for various http methods
50 this.methods = {};
51}
52
53/**
54 * Determine if the route handles a given method.
55 * @private
56 */
57
58Route.prototype._handles_method = function _handles_method(method) {
59 if (this.methods._all) {
60 return true;
61 }
62
63 var name = method.toLowerCase();
64
65 if (name === 'head' && !this.methods['head']) {
66 name = 'get';
67 }
68
69 return Boolean(this.methods[name]);
70};
71
72/**
73 * @return {Array} supported HTTP methods
74 * @private
75 */
76
77Route.prototype._options = function _options() {
78 var methods = Object.keys(this.methods);
79
80 // append automatic head
81 if (this.methods.get && !this.methods.head) {
82 methods.push('head');
83 }
84
85 for (var i = 0; i < methods.length; i++) {
86 // make upper case
87 methods[i] = methods[i].toUpperCase();
88 }
89
90 return methods;
91};
92
93/**
94 * dispatch req, res into this route
95 * @private
96 */
97
98Route.prototype.dispatch = function dispatch(req, res, done) {
99 var idx = 0;
100 var stack = this.stack;
101 if (stack.length === 0) {
102 return done();
103 }
104
105 var method = req.method.toLowerCase();
106 if (method === 'head' && !this.methods['head']) {
107 method = 'get';
108 }
109
110 req.route = this;
111
112 next();
113
114 function next(err) {
115 if (err && err === 'route') {
116 return done();
117 }
118
119 var layer = stack[idx++];
120 if (!layer) {
121 return done(err);
122 }
123
124 if (layer.method && layer.method !== method) {
125 return next(err);
126 }
127
128 if (err) {
129 layer.handle_error(err, req, res, next);
130 } else {
131 layer.handle_request(req, res, next);
132 }
133 }
134};
135
136/**
137 * Add a handler for all HTTP verbs to this route.
138 *
139 * Behaves just like middleware and can respond or call `next`
140 * to continue processing.
141 *
142 * You can use multiple `.all` call to add multiple handlers.
143 *
144 * function check_something(req, res, next){
145 * next();
146 * };
147 *
148 * function validate_user(req, res, next){
149 * next();
150 * };
151 *
152 * route
153 * .all(validate_user)
154 * .all(check_something)
155 * .get(function(req, res, next){
156 * res.send('hello world');
157 * });
158 *
159 * @param {function} handler
160 * @return {Route} for chaining
161 * @api public
162 */
163
164Route.prototype.all = function all() {
165 var handles = flatten(slice.call(arguments));
166
167 for (var i = 0; i < handles.length; i++) {
168 var handle = handles[i];
169
170 if (typeof handle !== 'function') {
171 var type = toString.call(handle);
172 var msg = 'Route.all() requires callback functions but got a ' + type;
173 throw new TypeError(msg);
174 }
175
176 var layer = Layer('/', {}, handle);
177 layer.method = undefined;
178
179 this.methods._all = true;
180 this.stack.push(layer);
181 }
182
183 return this;
184};
185
186methods.forEach(function(method){
187 Route.prototype[method] = function(){
188 var handles = flatten(slice.call(arguments));
189
190 for (var i = 0; i < handles.length; i++) {
191 var handle = handles[i];
192
193 if (typeof handle !== 'function') {
194 var type = toString.call(handle);
195 var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
196 throw new Error(msg);
197 }
198
199 debug('%s %s', method, this.path);
200
201 var layer = Layer('/', {}, handle);
202 layer.method = method;
203
204 this.methods[method] = true;
205 this.stack.push(layer);
206 }
207
208 return this;
209 };
210});