From ada01475731b80cdc798e2820906fcd0d00b6dae Mon Sep 17 00:00:00 2001 From: medfreeman Date: Wed, 25 Aug 2021 15:24:09 +0200 Subject: [PATCH] feat: add `exclusive` option --- API.md | 1 + lib/router.js | 4 +++- test/lib/router.js | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/API.md b/API.md index e8394db..5694996 100644 --- a/API.md +++ b/API.md @@ -31,6 +31,7 @@ Create a new router. | --- | --- | --- | | [opts] | Object | | | [opts.prefix] | String | prefix router paths | +| [opts.exclusive] | Boolean | only run last matched route's controller when there are multiple matches | **Example** Basic usage: diff --git a/lib/router.js b/lib/router.js index a7f0871..0087958 100644 --- a/lib/router.js +++ b/lib/router.js @@ -43,6 +43,7 @@ module.exports = Router; * * @alias module:koa-router * @param {Object=} opts + * @param {Boolean=false} opts.exclusive only run last matched route's controller when there are multiple matches * @param {String=} opts.prefix prefix router paths * @constructor */ @@ -60,6 +61,7 @@ function Router(opts) { 'POST', 'DELETE' ]; + this.exclusive = !!this.opts.exclusive; this.params = {}; this.stack = []; @@ -359,7 +361,7 @@ Router.prototype.routes = Router.prototype.middleware = function () { ctx._matchedRouteName = mostSpecificLayer.name; } - layerChain = matchedLayers.reduce(function(memo, layer) { + layerChain = (router.exclusive ? [mostSpecificLayer] : matchedLayers).reduce(function(memo, layer) { memo.push(function(ctx, next) { ctx.captures = layer.captures(path, ctx.captures); ctx.params = ctx.request.params = layer.params(path, ctx.captures, ctx.params); diff --git a/test/lib/router.js b/test/lib/router.js index b2a37b6..8ec19e6 100644 --- a/test/lib/router.js +++ b/test/lib/router.js @@ -246,6 +246,56 @@ describe('Router', function () { }) }); + it('runs multiple controllers when there are multiple matches', function (done) { + const app = new Koa(); + const router = new Router(); + + router + .get('users_single', '/users/:id(.*)', function (ctx, next) { + ctx.body = { single: true }; + next(); + }) + .get('users_all', '/users/all', function (ctx, next) { + ctx.body = Object.assign({}, ctx.body, { all: true }); + next(); + }); + + request(http.createServer(app.use(router.routes()).callback())) + .get('/users/all') + .expect(200) + .end(function (err, res) { + if (err) return done(err); + expect(res.body).to.have.property('single', true); + expect(res.body).to.have.property('all', true); + done(); + }) + }); + + it('runs only the last match when the \'exclusive\' option is enabled', function (done) { + const app = new Koa(); + const router = new Router({ exclusive: true }); + + router + .get('users_single', '/users/:id(.*)', function (ctx, next) { + ctx.body = { single: true }; + next(); + }) + .get('users_all', '/users/all', function (ctx, next) { + ctx.body = Object.assign({}, ctx.body, { all: true }); + next(); + }); + + request(http.createServer(app.use(router.routes()).callback())) + .get('/users/all') + .expect(200) + .end(function (err, res) { + if (err) return done(err); + expect(res.body).to.not.have.property('single'); + expect(res.body).to.have.property('all', true); + done(); + }) + }); + it('does not run subsequent middleware without calling next', function (done) { const app = new Koa(); const router = new Router();