UNPKG

4.15 kBJavaScriptView Raw
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 %o', 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 // signal to exit route
116 if (err && err === 'route') {
117 return done();
118 }
119
120 // signal to exit router
121 if (err && err === 'router') {
122 return done(err)
123 }
124
125 var layer = stack[idx++];
126 if (!layer) {
127 return done(err);
128 }
129
130 if (layer.method && layer.method !== method) {
131 return next(err);
132 }
133
134 if (err) {
135 layer.handle_error(err, req, res, next);
136 } else {
137 layer.handle_request(req, res, next);
138 }
139 }
140};
141
142/**
143 * Add a handler for all HTTP verbs to this route.
144 *
145 * Behaves just like middleware and can respond or call `next`
146 * to continue processing.
147 *
148 * You can use multiple `.all` call to add multiple handlers.
149 *
150 * function check_something(req, res, next){
151 * next();
152 * };
153 *
154 * function validate_user(req, res, next){
155 * next();
156 * };
157 *
158 * route
159 * .all(validate_user)
160 * .all(check_something)
161 * .get(function(req, res, next){
162 * res.send('hello world');
163 * });
164 *
165 * @param {function} handler
166 * @return {Route} for chaining
167 * @api public
168 */
169
170Route.prototype.all = function all() {
171 var handles = flatten(slice.call(arguments));
172
173 for (var i = 0; i < handles.length; i++) {
174 var handle = handles[i];
175
176 if (typeof handle !== 'function') {
177 var type = toString.call(handle);
178 var msg = 'Route.all() requires callback functions but got a ' + type;
179 throw new TypeError(msg);
180 }
181
182 var layer = Layer('/', {}, handle);
183 layer.method = undefined;
184
185 this.methods._all = true;
186 this.stack.push(layer);
187 }
188
189 return this;
190};
191
192methods.forEach(function(method){
193 Route.prototype[method] = function(){
194 var handles = flatten(slice.call(arguments));
195
196 for (var i = 0; i < handles.length; i++) {
197 var handle = handles[i];
198
199 if (typeof handle !== 'function') {
200 var type = toString.call(handle);
201 var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
202 throw new Error(msg);
203 }
204
205 debug('%s %o', method, this.path)
206
207 var layer = Layer('/', {}, handle);
208 layer.method = method;
209
210 this.methods[method] = true;
211 this.stack.push(layer);
212 }
213
214 return this;
215 };
216});