function Router(opts) { if (!(this instanceof Router)) { return new Router(opts); } this.opts = opts || {}; this.methods = this.opts.methods || [ 'HEAD', 'OPTIONS', 'GET', 'PUT', 'PATCH', 'POST', 'DELETE' ]; this.params = {}; this.stack = []; }
n/a
function Layer(path, methods, middleware, opts) { this.opts = opts || {}; this.name = this.opts.name || null; this.methods = []; this.paramNames = []; this.stack = Array.isArray(middleware) ? middleware : [middleware]; methods.forEach(function(method) { var l = this.methods.push(method.toUpperCase()); if (this.methods[l-1] === 'GET') { this.methods.unshift('HEAD'); } }, this); // ensure middleware is a function this.stack.forEach(function(fn) { var type = (typeof fn); if (type !== 'function') { throw new Error( methods.toString() + " `" + (this.opts.name || path) +"`: `middleware` " + "must be a function, not `" + type + "`" ); } }, this); this.path = path; this.regexp = pathToRegExp(path, this.paramNames, this.opts); debug('defined route %s %s', this.methods, this.opts.prefix + this.path); }
n/a
url = function (path, params) { return Layer.prototype.url.call({path: path}, params); }
...
## 5.4.0
- Expose matched route at `ctx._matchedRoute`.
## 5.3.0
- Register multiple routes with array of paths [#203](https://github.com/alexmingoia/koa-router/issue/143).
- Improved router.url() [#143](https://github.com/alexmingoia/koa-router/pull/143)
- Adds support for named routes and regular expressions
[#152](https://github.com/alexmingoia/koa-router/pull/152)
- Add support for custom throw functions for 405 and 501 responses [#206](https://github.com/alexmingoia/koa-router/pull/206)
## 5.2.3
- Fix for middleware running twice when nesting routes [#184](https://github.com/alexmingoia/koa-router/issues/184)
...
function Layer(path, methods, middleware, opts) { this.opts = opts || {}; this.name = this.opts.name || null; this.methods = []; this.paramNames = []; this.stack = Array.isArray(middleware) ? middleware : [middleware]; methods.forEach(function(method) { var l = this.methods.push(method.toUpperCase()); if (this.methods[l-1] === 'GET') { this.methods.unshift('HEAD'); } }, this); // ensure middleware is a function this.stack.forEach(function(fn) { var type = (typeof fn); if (type !== 'function') { throw new Error( methods.toString() + " `" + (this.opts.name || path) +"`: `middleware` " + "must be a function, not `" + type + "`" ); } }, this); this.path = path; this.regexp = pathToRegExp(path, this.paramNames, this.opts); debug('defined route %s %s', this.methods, this.opts.prefix + this.path); }
n/a
captures = function (path) { if (this.opts.ignoreCaptures) return []; return path.match(this.regexp).slice(1); }
...
if (!matched.route) return next();
var mostSpecificPath = matched.pathAndMethod[matched.pathAndMethod.length - 1].path;
ctx._matchedRoute = mostSpecificPath;
layerChain = matched.pathAndMethod.reduce(function(memo, layer) {
memo.push(function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);
...
match = function (path) { return this.regexp.test(path); }
...
Private API changed to separate context parameter decoration from route
matching. `Router#match` and `Route#match` are now pure functions that return
an array of routes that match the URL path.
For modules using this private API that need to determine if a method and path
match a route, `route.methods` must be checked against the routes returned from
`router.match()`:
```javascript
var matchedRoute = router.match(path).filter(function (route) {
return ~route.methods.indexOf(method);
}).shift();
```
...
param = function (param, fn) { var stack = this.stack; var params = this.paramNames; var middleware = function (ctx, next) { return fn.call(this, ctx.params[param], ctx, next); }; middleware.param = param; var names = params.map(function (p) { return p.name; }); var x = names.indexOf(param); if (x > -1) { // iterate through the stack, to figure out where to place the handler fn stack.some(function (fn, i) { // param handlers are always first, so when we find an fn w/o a param property, stop here // if the param handler at this part of the stack comes after the one we are adding, stop here if (!fn.param || names.indexOf(fn.param) > x) { // inject this param handler right before the current item stack.splice(i, 0, middleware); return true; // then break the loop } }); } return this; }
...
* [.routes](#module_koa-router--Router+routes) ⇒ <code>function</code>
* [.use([path], middleware, [...])](#module_koa-router--Router+use) ⇒ <code>Router</code>
* [.prefix(prefix)](#module_koa-router--Router+prefix) ⇒ <code>Router</code>
* [.allowedMethods([options])](#module_koa-router--Router+allowedMethods) ⇒ <code>function</code>
* [.redirect(source, destination, code)](#module_koa-router--Router+redirect) ⇒ <code>Router</code>
* [.route(name)](#module_koa-router--Router+route) ⇒ <code>Layer</code> | <code>false
</code>
* [.url(name, params)](#module_koa-router--Router+url) ⇒ <code>String</code> | <code>
;Error</code>
* [.param(param, middleware)](#module_koa-router--Router+param) ⇒ <code>
;Router</code>
* _static_
* [.url(path, params)](#module_koa-router--Router.url) ⇒ <code>String</code>
<a name="exp_module_koa-router--Router"></a>
### Router ⏏
**Kind**: Exported class
<a name="new_module_koa-router--Router_new"></a>
...
params = function (path, captures, existingParams) { var params = existingParams || {}; for (var len = captures.length, i=0; i<len; i++) { if (this.paramNames[i]) { var c = captures[i]; params[this.paramNames[i].name] = c ? safeDecodeURIComponent(c) : c; } } return params; }
...
var mostSpecificPath = matched.pathAndMethod[matched.pathAndMethod.length - 1].path;
ctx._matchedRoute = mostSpecificPath;
layerChain = matched.pathAndMethod.reduce(function(memo, layer) {
memo.push(function(ctx, next) {
ctx.captures = layer.captures(path, ctx.captures);
ctx.params = layer.params(path, ctx.captures, ctx.params);
return next();
});
return memo.concat(layer.stack);
}, []);
return compose(layerChain)(ctx, next);
};
...
setPrefix = function (prefix) { if (this.path) { this.path = prefix + this.path; this.paramNames = []; this.regexp = pathToRegExp(this.path, this.paramNames, this.opts); } return this; }
...
if (hasPath) {
path = middleware.shift();
}
middleware.forEach(function (m) {
if (m.router) {
m.router.stack.forEach(function (nestedLayer) {
if (path) nestedLayer.setPrefix(path);
if (router.opts.prefix) nestedLayer.setPrefix(router.opts.prefix);
router.stack.push(nestedLayer);
});
if (router.params) {
Object.keys(router.params).forEach(function (key) {
m.router.param(key, router.params[key]);
...
url = function (params) { var args = params; var url = this.path; var toPath = pathToRegExp.compile(url); // argument is of form { key: val } if (typeof params != 'object') { args = Array.prototype.slice.call(arguments); } if (args instanceof Array) { var tokens = pathToRegExp.parse(url); var replace = {}; for (var len = tokens.length, i=0, j=0; i<len; i++) { if (tokens[i].name) replace[tokens[i].name] = args[j++]; } return toPath(replace); } else { return toPath(params); } }
...
## 5.4.0
- Expose matched route at `ctx._matchedRoute`.
## 5.3.0
- Register multiple routes with array of paths [#203](https://github.com/alexmingoia/koa-router/issue/143).
- Improved router.url() [#143](https://github.com/alexmingoia/koa-router/pull/143)
- Adds support for named routes and regular expressions
[#152](https://github.com/alexmingoia/koa-router/pull/152)
- Add support for custom throw functions for 405 and 501 responses [#206](https://github.com/alexmingoia/koa-router/pull/206)
## 5.2.3
- Fix for middleware running twice when nesting routes [#184](https://github.com/alexmingoia/koa-router/issues/184)
...