Skip to content

Commit a0afed7

Browse files
ajfranzoiagabegorelick
authored andcommitted
feat: store matched routes in request
closes #34 closes #85
1 parent c512eec commit a0afed7

File tree

4 files changed

+211
-16
lines changed

4 files changed

+211
-16
lines changed

HISTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ unreleased
88
99
1010
11+
* Store matched routes in request
1112

1213
2.0.0-alpha.1 / 2018-07-27
1314
==========================

index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ Router.prototype.handle = function handle(req, res, callback) {
166166
// manage inter-router variables
167167
var parentParams = req.params
168168
var parentUrl = req.baseUrl || ''
169-
var done = restore(callback, req, 'baseUrl', 'next', 'params')
169+
var parentMatchedRoutes = req.matchedRoutes
170+
var done = restore(callback, req, 'baseUrl', 'next', 'params', 'matchedRoutes')
170171

171172
// setup next layer
172173
req.next = next
@@ -199,6 +200,7 @@ Router.prototype.handle = function handle(req, res, callback) {
199200
req.baseUrl = parentUrl
200201
req.url = protohost + removed + req.url.substr(protohost.length)
201202
removed = ''
203+
req.matchedRoutes = parentMatchedRoutes
202204
}
203205

204206
// signal to exit router
@@ -287,6 +289,11 @@ Router.prototype.handle = function handle(req, res, callback) {
287289
return next(layerError || err)
288290
}
289291

292+
if (layer.path) {
293+
req.matchedRoutes = req.matchedRoutes || []
294+
req.matchedRoutes.push(layer.matchedPath.path)
295+
}
296+
290297
if (route) {
291298
return layer.handle_request(req, res, next)
292299
}
@@ -342,7 +349,7 @@ Router.prototype.process_params = function process_params(layer, called, req, re
342349
var params = this.params
343350

344351
// captured parameters from the layer, keys and values
345-
var keys = layer.keys
352+
var keys = layer.matchedPath && layer.matchedPath.keys
346353

347354
// fast track
348355
if (!keys || keys.length === 0) {

lib/layer.js

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,18 @@ function Layer(p, options, fn) {
3333
return new Layer(p, options, fn)
3434
}
3535

36-
debug('new %o', path)
36+
debug('new %o', paths)
3737
var opts = options || {}
3838

3939
// If not in strict allow both with or without trailing slash
40-
var path = p
40+
var paths = p
4141
if (!opts.strict) {
42-
if (!Array.isArray(path) && path !== '/' && path[path.length - 1] === '/') {
43-
path = path.substr(0, path.length - 1)
42+
if (!Array.isArray(paths) && paths !== '/' && paths[paths.length - 1] === '/') {
43+
paths = paths.substr(0, paths.length - 1)
4444
} else {
45-
for (var i = 0; i < path.length; i++) {
46-
if (path[i] !== '/' && path[i][path[i].length - 1] === '/') {
47-
path[i] = path[i].substr(0, path[i].length - 1)
45+
for (var i = 0; i < paths.length; i++) {
46+
if (paths[i] !== '/' && paths[i][paths[i].length - 1] === '/') {
47+
paths[i] = paths[i].substr(0, paths[i].length - 1)
4848
}
4949
}
5050
}
@@ -54,11 +54,22 @@ function Layer(p, options, fn) {
5454
this.name = fn.name || '<anonymous>'
5555
this.params = undefined
5656
this.path = undefined
57-
this.regexp = pathRegexp(path, this.keys = [], opts)
57+
this.matchedPath = undefined
5858

5959
// set fast path flags
60-
this.regexp.fast_star = path === '*'
61-
this.regexp.fast_slash = path === '/' && opts.end === false
60+
this.fastStar = paths === '*'
61+
this.fastSlash = paths === '/' && opts.end === false
62+
63+
this.paths = (!Array.isArray(paths) ? [paths] : paths).map(function (path) {
64+
var keys = []
65+
var pathObj = {
66+
path: path,
67+
keys: keys,
68+
regexp: pathRegexp(path, keys, opts)
69+
}
70+
71+
return pathObj
72+
})
6273
}
6374

6475
/**
@@ -137,29 +148,39 @@ Layer.prototype.handle_request = function handle(req, res, next) {
137148

138149
Layer.prototype.match = function match(path) {
139150
var match
151+
var checkPath
140152

141153
if (path != null) {
142154
// fast path non-ending match for / (any path matches)
143-
if (this.regexp.fast_slash) {
155+
if (this.fastSlash) {
144156
this.params = {}
145157
this.path = ''
158+
this.matchedPath = this.paths[0]
146159
return true
147160
}
148161

149162
// fast path for * (everything matched in a param)
150-
if (this.regexp.fast_star) {
163+
if (this.fastStar) {
151164
this.params = {'0': decode_param(path)}
152165
this.path = path
166+
this.matchedPath = this.paths[0]
153167
return true
154168
}
155169

156170
// match the path
157-
match = this.regexp.exec(path)
171+
for (var i = 0; i < this.paths.length; i++) {
172+
checkPath = this.paths[i]
173+
if (match = checkPath.regexp.exec(path)) {
174+
this.matchedPath = checkPath
175+
break
176+
}
177+
}
158178
}
159179

160180
if (!match) {
161181
this.params = undefined
162182
this.path = undefined
183+
this.matchedPath = undefined
163184
return false
164185
}
165186

@@ -172,7 +193,7 @@ Layer.prototype.match = function match(path) {
172193
var params = this.params
173194

174195
for (var i = 1; i < match.length; i++) {
175-
var key = keys[i - 1]
196+
var key = this.matchedPath.keys[i - 1]
176197
var prop = key.name
177198
var val = decode_param(match[i])
178199

test/router.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,172 @@ describe('Router', function () {
12461246
.expect(200, 'saw GET /bar', done)
12471247
})
12481248
})
1249+
1250+
describe('req.matchedRoutes', function () {
1251+
it('should be set if there is a match', function (done) {
1252+
var router = new Router()
1253+
var server = createServer(router)
1254+
var matchedRoutes
1255+
1256+
router.get('/foo', function (req, res, next) {
1257+
matchedRoutes = req.matchedRoutes
1258+
next()
1259+
})
1260+
router.use(saw)
1261+
1262+
request(server)
1263+
.get('/foo')
1264+
.expect(200, 'saw GET /foo', function (err, res) {
1265+
assert.deepEqual(matchedRoutes, ['/foo'])
1266+
done(err)
1267+
})
1268+
})
1269+
1270+
it('should be undefined if there is not a match', function (done) {
1271+
var router = new Router()
1272+
var server = createServer(router)
1273+
var matchedRoutes
1274+
1275+
router.use(function (req, res, next) {
1276+
matchedRoutes = req.matchedRoutes
1277+
next()
1278+
})
1279+
1280+
request(server)
1281+
.get('/foo')
1282+
.expect(404, function (err, res) {
1283+
assert.strictEqual(matchedRoutes, undefined)
1284+
done(err)
1285+
})
1286+
})
1287+
1288+
it('should work with sub-routers', function (done) {
1289+
var router = new Router()
1290+
var fooRouter = new Router()
1291+
var server = createServer(router)
1292+
var matchedFooRoutes
1293+
var matchedBarRoutes
1294+
1295+
router.use('/foo', function (req, res, next) {
1296+
matchedFooRoutes = req.matchedRoutes
1297+
next()
1298+
}, fooRouter)
1299+
fooRouter.get('/bar', function (req, res, next) {
1300+
matchedBarRoutes = req.matchedRoutes
1301+
next()
1302+
})
1303+
router.use(saw)
1304+
1305+
request(server)
1306+
.get('/foo/bar')
1307+
.expect(200, 'saw GET /foo/bar', function (err, res) {
1308+
assert.deepEqual(matchedFooRoutes, ['/foo'])
1309+
assert.deepEqual(matchedBarRoutes, ['/foo', '/bar'])
1310+
done(err)
1311+
})
1312+
})
1313+
1314+
it('should be undefined if sub-router did not match', function (done) {
1315+
var router = new Router()
1316+
var fooRouter = new Router()
1317+
var server = createServer(router)
1318+
var matchedRoutes
1319+
1320+
router.use('/foo', fooRouter)
1321+
fooRouter.get('/bar', function (req, res, next) {
1322+
matchedRoutes = req.matchedRoutes
1323+
next()
1324+
})
1325+
router.use(saw)
1326+
1327+
request(server)
1328+
.get('/foo/baz')
1329+
.expect(200, 'saw GET /foo/baz', function (err, res) {
1330+
assert.strictEqual(matchedRoutes, undefined)
1331+
done(err)
1332+
})
1333+
})
1334+
1335+
it('should work with regexp-defined routes', function (done) {
1336+
var router = new Router()
1337+
var server = createServer(router)
1338+
var matchedRoutes
1339+
var regexp = /fo+/
1340+
1341+
router.get(regexp, function (req, res, next) {
1342+
matchedRoutes = req.matchedRoutes
1343+
next()
1344+
})
1345+
router.use(saw)
1346+
1347+
request(server)
1348+
.get('/foo')
1349+
.expect(200, 'saw GET /foo', function (err, res) {
1350+
assert.deepEqual(matchedRoutes, [regexp])
1351+
done(err)
1352+
})
1353+
})
1354+
1355+
it('should support routes defined with arrays of paths', function (done) {
1356+
var router = new Router()
1357+
var server = createServer(router)
1358+
var matchedRoutes
1359+
1360+
router.get(['/foo', '/bar/:id'], function (req, res, next) {
1361+
matchedRoutes = req.matchedRoutes
1362+
next()
1363+
})
1364+
router.use(saw)
1365+
1366+
request(server)
1367+
.get('/foo')
1368+
.expect(200, 'saw GET /foo', function (err, res) {
1369+
if (err) {
1370+
return done(err)
1371+
}
1372+
assert.deepEqual(matchedRoutes, ['/foo'])
1373+
1374+
request(server)
1375+
.get('/bar/1')
1376+
.expect(200, 'saw GET /bar/1', function (err, res) {
1377+
if (err) {
1378+
return done(err)
1379+
}
1380+
assert.deepEqual(matchedRoutes, ['/bar/:id'])
1381+
done()
1382+
})
1383+
})
1384+
})
1385+
1386+
it('should support sibling routes at same path', function (done) {
1387+
var router = new Router()
1388+
var server = createServer(router)
1389+
var matchedRoutes1
1390+
var matchedRoutes2
1391+
1392+
router.get('/foo', function (req, res, next) {
1393+
matchedRoutes1 = req.matchedRoutes
1394+
next()
1395+
})
1396+
router.get('/foo', function (req, res, next) {
1397+
matchedRoutes2 = req.matchedRoutes
1398+
next()
1399+
})
1400+
router.use(saw)
1401+
1402+
request(server)
1403+
.get('/foo')
1404+
.expect(200, 'saw GET /foo', function (err, res) {
1405+
if (err) {
1406+
return done(err)
1407+
}
1408+
assert.deepEqual(matchedRoutes1, ['/foo'])
1409+
assert.deepEqual(matchedRoutes2, ['/foo'])
1410+
1411+
done()
1412+
})
1413+
})
1414+
})
12491415
})
12501416

12511417
function helloWorld(req, res) {

0 commit comments

Comments
 (0)