UNPKG

@eggjs/router

Version:

Router middleware for egg/koa. Provides RESTful resource routing.

783 lines 50.3 kB
/** * RESTful resource routing middleware for eggjs. */ import { debuglog } from 'node:util'; import assert from 'node:assert'; import compose from 'koa-compose'; import HttpError from 'http-errors'; import methods from 'methods'; import { Layer } from './Layer.js'; const debug = debuglog('@eggjs/router:Router'); export class Router { opts; methods; /** Layer stack */ stack = []; params = {}; /** * Create a new router. * * @example * * Basic usage: * * ```javascript * var Koa = require('koa'); * var Router = require('koa-router'); * * var app = new Koa(); * var router = new Router(); * * router.get('/', (ctx, next) => { * // ctx.router available * }); * * app * .use(router.routes()) * .use(router.allowedMethods()); * ``` * * @alias module:koa-router * @param {Object=} opts optional * @param {String=} opts.prefix prefix router paths * @class */ constructor(opts) { this.opts = opts ?? {}; this.methods = this.opts.methods ?? [ 'HEAD', 'OPTIONS', 'GET', 'PUT', 'PATCH', 'POST', 'DELETE', ]; } use(pathOrMiddleware, ...middlewares) { // support array of paths // use(paths, ...middlewares) if (Array.isArray(pathOrMiddleware) && typeof pathOrMiddleware[0] === 'string') { for (const path of pathOrMiddleware) { this.use(path, ...middlewares); } return this; } let path = ''; let hasPath = false; if (typeof pathOrMiddleware === 'string') { // use(path, ...middlewares) path = pathOrMiddleware; hasPath = true; } else if (typeof pathOrMiddleware === 'function') { // use(...middlewares) middlewares = [pathOrMiddleware, ...middlewares]; } for (const m of middlewares) { if (m.router) { for (const nestedLayer of m.router.stack) { if (path) { nestedLayer.setPrefix(path); } if (this.opts.prefix) { nestedLayer.setPrefix(this.opts.prefix); } this.stack.push(nestedLayer); } if (this.params) { for (const key in this.params) { m.router.param(key, this.params[key]); } } } else { this.register(path || '(.*)', [], m, { end: false, ignoreCaptures: !hasPath }); } } return this; } /** * Set the path prefix for a Router instance that was already initialized. * * @example * * ```javascript * router.prefix('/things/:thing_id') * ``` * * @param {String} prefix prefix string * @return {Router} router instance */ prefix(prefix) { prefix = prefix.replace(/\/$/, ''); this.opts.prefix = prefix; for (const layer of this.stack) { layer.setPrefix(prefix); } return this; } /** * Returns router middleware which dispatches a route matching the request. * * @return {Function} middleware function */ routes() { const dispatch = (ctx, next) => { const routerPath = this.opts.routerPath || ctx.routerPath || ctx.path; const matched = this.match(routerPath, ctx.method); debug('dispatch: %s %s, routerPath: %s, matched: %s', ctx.method, ctx.path, routerPath, matched.route); if (ctx.matched) { ctx.matched.push(...matched.path); } else { ctx.matched = matched.path; } ctx.router = this; if (!matched.route) { return next(); } const matchedLayers = matched.pathAndMethod; const layerChain = matchedLayers.reduce((memo, layer) => { memo.push((ctx, next) => { // ctx.captures = layer.captures(routerPath, ctx.captures); ctx.captures = layer.captures(routerPath); ctx.params = layer.params(routerPath, ctx.captures, ctx.params); // ctx._matchedRouteName & ctx._matchedRoute for compatibility ctx._matchedRouteName = ctx.routerName = layer.name; if (!layer.name) { ctx._matchedRouteName = undefined; } ctx._matchedRoute = ctx.routerPath = layer.path; return next(); }); return memo.concat(layer.stack); }, []); return compose(layerChain)(ctx, next); }; dispatch.router = this; return dispatch; } /** * @alias to routes() */ middleware() { return this.routes(); } /** * Returns separate middleware for responding to `OPTIONS` requests with * an `Allow` header containing the allowed methods, as well as responding * with `405 Method Not Allowed` and `501 Not Implemented` as appropriate. * * @example * * ```javascript * var Koa = require('koa'); * var Router = require('koa-router'); * * var app = new Koa(); * var router = new Router(); * * app.use(router.routes()); * app.use(router.allowedMethods()); * ``` * * **Example with [Boom](https://github.com/hapijs/boom)** * * ```javascript * var Koa = require('koa'); * var Router = require('koa-router'); * var Boom = require('boom'); * * var app = new Koa(); * var router = new Router(); * * app.use(router.routes()); * app.use(router.allowedMethods({ * throw: true, * notImplemented: () => new Boom.notImplemented(), * methodNotAllowed: () => new Boom.methodNotAllowed() * })); * ``` * * @param {Object=} options optional params * @param {Boolean=} options.throw throw error instead of setting status and header * @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error * @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error * @return {Function} middleware function */ allowedMethods(options) { const implemented = this.methods; return async function allowedMethods(ctx, next) { await next(); if (ctx.status && ctx.status !== 404) return; const allowed = {}; ctx.matched.forEach((route) => { route.methods.forEach(method => { allowed[method] = method; }); }); const allowedMethods = Object.keys(allowed); if (!implemented.includes(ctx.method)) { if (options?.throw) { let notImplementedThrowable; if (typeof options?.notImplemented === 'function') { notImplementedThrowable = options.notImplemented(); // set whatever the user returns from their function } else { notImplementedThrowable = new HttpError.NotImplemented(); } throw notImplementedThrowable; } else { ctx.status = 501; ctx.set('Allow', allowedMethods.join(', ')); } } else if (allowedMethods.length > 0) { if (ctx.method === 'OPTIONS') { ctx.status = 200; ctx.body = ''; ctx.set('Allow', allowedMethods.join(', ')); } else if (!allowed[ctx.method]) { if (options?.throw) { let notAllowedThrowable; if (typeof options?.methodNotAllowed === 'function') { notAllowedThrowable = options.methodNotAllowed(); // set whatever the user returns from their function } else { notAllowedThrowable = new HttpError.MethodNotAllowed(); } throw notAllowedThrowable; } else { ctx.status = 405; ctx.set('Allow', allowedMethods.join(', ')); } } } }; } /** * Redirect `source` to `destination` URL with optional 30x status `code`. * * Both `source` and `destination` can be route names. * * ```javascript * router.redirect('/login', 'sign-in'); * ``` * * This is equivalent to: * * ```javascript * router.all('/login', ctx => { * ctx.redirect('/sign-in'); * ctx.status = 301; * }); * ``` * * @param {String} source URL or route name. * @param {String} destination URL or route name. * @param {Number=} status HTTP status code (default: 301). * @return {Router} router instance */ redirect(source, destination, status = 301) { // lookup source route by name if (source[0] !== '/') { const routeUrl = this.url(source); if (routeUrl instanceof Error) { throw routeUrl; } source = routeUrl; } // lookup destination route by name if (destination[0] !== '/') { const routeUrl = this.url(destination); if (routeUrl instanceof Error) { throw routeUrl; } destination = routeUrl; } return this.all(source, ctx => { ctx.redirect(destination); ctx.status = status; }); } /** * Create and register a route. * * @param {String|RegExp|(String|RegExp)[]} path Path string. * @param {String[]} methods Array of HTTP verbs. * @param {Function|Function[]} middleware Multiple middleware also accepted. * @param {Object} [opts] optional params * @private */ register(path, methods, middleware, opts) { // support array of paths if (Array.isArray(path)) { const routes = []; for (const p of path) { const route = this.#register(p, methods, middleware, opts); routes.push(route); } return routes; } // create route const route = this.#register(path, methods, middleware, opts); return route; } #register(path, methods, middleware, opts) { opts = opts ?? {}; // create route const route = new Layer(path, methods, middleware, { end: opts.end === false ? opts.end : true, name: opts.name, sensitive: opts.sensitive ?? this.opts.sensitive ?? false, strict: opts.strict ?? this.opts.strict ?? false, prefix: opts.prefix ?? this.opts.prefix ?? '', ignoreCaptures: opts.ignoreCaptures, }); // FIXME: why??? if (this.opts.prefix) { route.setPrefix(this.opts.prefix); } // add parameter middleware to the new route layer for (const param in this.params) { route.param(param, this.params[param]); } this.stack.push(route); return route; } /** * Lookup route with given `name`. * * @param {String} name route name * @return {Layer|false} layer instance of false */ route(name) { for (const route of this.stack) { if (route.name === name) { return route; } } return false; } /** * Generate URL for route. Takes a route name and map of named `params`. * * @example * * ```javascript * router.get('user', '/users/:id', (ctx, next) => { * // ... * }); * * router.url('user', 3); * // => "/users/3" * * router.url('user', { id: 3 }); * // => "/users/3" * * router.use((ctx, next) => { * // redirect to named route * ctx.redirect(ctx.router.url('sign-in')); * }) * * router.url('user', { id: 3 }, { query: { limit: 1 } }); * // => "/users/3?limit=1" * * router.url('user', { id: 3 }, { query: "limit=1" }); * // => "/users/3?limit=1" * ``` */ url(name, params, ...paramsOrOptions) { const route = this.route(name); if (route) { return route.url(params, ...paramsOrOptions); } return new Error(`No route found for name: ${name}`); } /** * Generate URL from url pattern and given `params`. * * @example * * ```javascript * var url = Router.url('/users/:id', { id: 1 }); * // => "/users/1" * ``` * * @param {String} path url pattern * @param {Object} params url parameters * @return {String} url string */ static url(path, params, ...paramsOrOptions) { return Layer.prototype.url.call({ path }, params, ...paramsOrOptions); } /** * Match given `path` and return corresponding routes. * * @param {String} path path string * @param {String} method method name * @return {Object.<path, pathAndMethod>} returns layers that matched path and * path and method. * @private */ match(path, method) { const matched = { // matched path path: [], // matched path and method(including none method) pathAndMethod: [], // method matched or not route: false, }; for (const layer of this.stack) { debug('test %s %s', layer.path, layer.regexp); if (layer.match(path)) { matched.path.push(layer); if (layer.methods.length === 0 || layer.methods.includes(method)) { matched.pathAndMethod.push(layer); if (layer.methods.length > 0) { matched.route = true; } } // if (layer.methods.length === 0) { // matched.pathAndMethod.push(layer); // } else if (layer.methods.includes(method)) { // matched.pathAndMethod.push(layer); // matched.route = true; // } } } return matched; } /** * Run middleware for named route parameters. Useful for auto-loading or * validation. * * @example * * ```javascript * router * .param('user', (id, ctx, next) => { * ctx.user = users[id]; * if (!ctx.user) return ctx.status = 404; * return next(); * }) * .get('/users/:user', ctx => { * ctx.body = ctx.user; * }) * .get('/users/:user/friends', ctx => { * return ctx.user.getFriends().then(function(friends) { * ctx.body = friends; * }); * }) * // /users/3 => {"id": 3, "name": "Alex"} * // /users/3/friends => [{"id": 4, "name": "TJ"}] * ``` * * @param {String} param param * @param {Function} middleware route middleware * @return {Router} instance */ param(param, middleware) { this.params[param] = middleware; for (const route of this.stack) { route.param(param, middleware); } return this; } _formatRouteParams(nameOrPath, pathOrMiddleware, middlewares) { const options = {}; let path; if (typeof nameOrPath === 'string' && nameOrPath.startsWith('/')) { // verb(method, path, ...middlewares) path = nameOrPath; middlewares = [pathOrMiddleware, ...middlewares]; if (typeof pathOrMiddleware === 'string') { // verb(method, path, controllerString) // set controller name to router name options.name = pathOrMiddleware; } } else if (nameOrPath instanceof RegExp) { // verb(method, pathRegex, ...middlewares) path = nameOrPath; middlewares = [pathOrMiddleware, ...middlewares]; if (typeof pathOrMiddleware === 'string') { // verb(method, pathRegex, controllerString) // set controller name to router name options.name = pathOrMiddleware; } } else if (Array.isArray(nameOrPath)) { // verb(method, paths, ...middlewares) path = nameOrPath; middlewares = [pathOrMiddleware, ...middlewares]; if (typeof pathOrMiddleware === 'string') { // verb(method, pathRegex, controllerString) // set controller name to router name options.name = pathOrMiddleware; } } else if (typeof pathOrMiddleware === 'string' || pathOrMiddleware instanceof RegExp) { // verb(method, name, path, ...middlewares) path = pathOrMiddleware; assert(typeof nameOrPath === 'string', 'route name should be string'); options.name = nameOrPath; } else if (Array.isArray(pathOrMiddleware)) { // verb(method, name, paths, ...middlewares) path = pathOrMiddleware; assert(typeof nameOrPath === 'string', 'route name should be string'); options.name = nameOrPath; } else { // verb(method, path, ...middlewares) path = nameOrPath; middlewares = [pathOrMiddleware, ...middlewares]; } return { path, middlewares, options, }; } /** * Create `router.verb()` methods, where *verb* is one of the HTTP verbs such * as `router.get()` or `router.post()`. * * Match URL patterns to callback functions or controller actions using `router.verb()`, * where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`. * * Additionally, `router.all()` can be used to match against all methods. * * ```javascript * router * .get('/', (ctx, next) => { * ctx.body = 'Hello World!'; * }) * .post('/users', (ctx, next) => { * // ... * }) * .put('/users/:id', (ctx, next) => { * // ... * }) * .del('/users/:id', (ctx, next) => { * // ... * }) * .all('/users/:id', (ctx, next) => { * // ... * }); * ``` * * When a route is matched, its path is available at `ctx._matchedRoute` and if named, * the name is available at `ctx._matchedRouteName` * * Route paths will be translated to regular expressions using * [path-to-regexp](https://github.com/pillarjs/path-to-regexp). * * Query strings will not be considered when matching requests. * * #### Named routes * * Routes can optionally have names. This allows generation of URLs and easy * renaming of URLs during development. * * ```javascript * router.get('user', '/users/:id', (ctx, next) => { * // ... * }); * * router.url('user', 3); * // => "/users/3" * ``` * * #### Multiple middleware * * Multiple middleware may be given: * * ```javascript * router.get( * '/users/:id', * (ctx, next) => { * return User.findOne(ctx.params.id).then(function(user) { * ctx.user = user; * next(); * }); * }, * ctx => { * console.log(ctx.user); * // => { id: 17, name: "Alex" } * } * ); * ``` * * ### Nested routers * * Nesting routers is supported: * * ```javascript * var forums = new Router(); * var posts = new Router(); * * posts.get('/', (ctx, next) => {...}); * posts.get('/:pid', (ctx, next) => {...}); * forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods()); * * // responds to "/forums/123/posts" and "/forums/123/posts/123" * app.use(forums.routes()); * ``` * * #### Router prefixes * * Route paths can be prefixed at the router level: * * ```javascript * var router = new Router({ * prefix: '/users' * }); * * router.get('/', ...); // responds to "/users" * router.get('/:id', ...); // responds to "/users/:id" * ``` * * #### URL parameters * * Named route parameters are captured and added to `ctx.params`. * * ```javascript * router.get('/:category/:title', (ctx, next) => { * console.log(ctx.params); * // => { category: 'programming', title: 'how-to-node' } * }); * ``` * * The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is * used to convert paths to regular expressions. * */ verb(method, nameOrPath, pathOrMiddleware, ...middleware) { const { options, path, middlewares } = this._formatRouteParams(nameOrPath, pathOrMiddleware, middleware); if (typeof method === 'string') { method = [method]; } this.register(path, method, middlewares, options); return this; } all(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb(methods, nameOrPath, pathOrMiddleware, ...middlewares); } acl(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('acl', nameOrPath, pathOrMiddleware, ...middlewares); } bind(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('bind', nameOrPath, pathOrMiddleware, ...middlewares); } checkout(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('checkout', nameOrPath, pathOrMiddleware, ...middlewares); } connect(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('connect', nameOrPath, pathOrMiddleware, ...middlewares); } copy(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('copy', nameOrPath, pathOrMiddleware, ...middlewares); } delete(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares); } del(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('delete', nameOrPath, pathOrMiddleware, ...middlewares); } get(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('get', nameOrPath, pathOrMiddleware, ...middlewares); } query(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('query', nameOrPath, pathOrMiddleware, ...middlewares); } head(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('head', nameOrPath, pathOrMiddleware, ...middlewares); } link(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('link', nameOrPath, pathOrMiddleware, ...middlewares); } lock(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('lock', nameOrPath, pathOrMiddleware, ...middlewares); } ['m-search'](nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('m-search', nameOrPath, pathOrMiddleware, ...middlewares); } merge(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('merge', nameOrPath, pathOrMiddleware, ...middlewares); } mkactivity(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('mkactivity', nameOrPath, pathOrMiddleware, ...middlewares); } mkcalendar(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('mkcalendar', nameOrPath, pathOrMiddleware, ...middlewares); } mkcol(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('mkcol', nameOrPath, pathOrMiddleware, ...middlewares); } move(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('move', nameOrPath, pathOrMiddleware, ...middlewares); } notify(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('notify', nameOrPath, pathOrMiddleware, ...middlewares); } options(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('options', nameOrPath, pathOrMiddleware, ...middlewares); } patch(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('patch', nameOrPath, pathOrMiddleware, ...middlewares); } post(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('post', nameOrPath, pathOrMiddleware, ...middlewares); } propfind(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('propfind', nameOrPath, pathOrMiddleware, ...middlewares); } proppatch(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('proppatch', nameOrPath, pathOrMiddleware, ...middlewares); } purge(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('purge', nameOrPath, pathOrMiddleware, ...middlewares); } put(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('put', nameOrPath, pathOrMiddleware, ...middlewares); } rebind(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('rebind', nameOrPath, pathOrMiddleware, ...middlewares); } report(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('report', nameOrPath, pathOrMiddleware, ...middlewares); } search(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('search', nameOrPath, pathOrMiddleware, ...middlewares); } source(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('source', nameOrPath, pathOrMiddleware, ...middlewares); } subscribe(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('subscribe', nameOrPath, pathOrMiddleware, ...middlewares); } trace(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('trace', nameOrPath, pathOrMiddleware, ...middlewares); } unbind(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('unbind', nameOrPath, pathOrMiddleware, ...middlewares); } unlink(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('unlink', nameOrPath, pathOrMiddleware, ...middlewares); } unlock(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('unlock', nameOrPath, pathOrMiddleware, ...middlewares); } unsubscribe(nameOrPath, pathOrMiddleware, ...middlewares) { return this.verb('unsubscribe', nameOrPath, pathOrMiddleware, ...middlewares); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL1JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckMsT0FBTyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBQ2pDLE9BQU8sT0FBTyxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLFNBQVMsTUFBTSxhQUFhLENBQUM7QUFDcEMsT0FBTyxPQUFPLE1BQU0sU0FBUyxDQUFDO0FBQzlCLE9BQU8sRUFBRSxLQUFLLEVBQW1CLE1BQU0sWUFBWSxDQUFDO0FBR3BELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0FBb0MvQyxNQUFNLE9BQU8sTUFBTTtJQUNSLElBQUksQ0FBZ0I7SUFDcEIsT0FBTyxDQUFXO0lBQzNCLGtCQUFrQjtJQUNULEtBQUssR0FBWSxFQUFFLENBQUM7SUFDcEIsTUFBTSxHQUF3QyxFQUFFLENBQUM7SUFFMUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQTJCRztJQUNILFlBQVksSUFBb0I7UUFDOUIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUk7WUFDbEMsTUFBTTtZQUNOLFNBQVM7WUFDVCxLQUFLO1lBQ0wsS0FBSztZQUNMLE9BQU87WUFDUCxNQUFNO1lBQ04sUUFBUTtTQUNULENBQUM7SUFDSixDQUFDO0lBZ0NELEdBQUcsQ0FBQyxnQkFBb0QsRUFBRSxHQUFHLFdBQTZCO1FBQ3hGLHlCQUF5QjtRQUN6Qiw2QkFBNkI7UUFDN0IsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLElBQUksT0FBTyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUMv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