@koa/router 13.1.1 → 15.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/router.js DELETED
@@ -1,824 +0,0 @@
1
- /**
2
- * RESTful resource routing middleware for koa.
3
- *
4
- * @author Alex Mingoia <talk@alexmingoia.com>
5
- * @link https://github.com/alexmingoia/koa-router
6
- */
7
- const http = require('node:http');
8
-
9
- const debug = require('debug')('koa-router');
10
-
11
- const compose = require('koa-compose');
12
- const HttpError = require('http-errors');
13
- const { pathToRegexp } = require('path-to-regexp');
14
-
15
- const Layer = require('./layer');
16
-
17
- const methods = http.METHODS.map((method) => method.toLowerCase());
18
-
19
- /**
20
- * @module koa-router
21
- */
22
- class Router {
23
- /**
24
- * Create a new router.
25
- *
26
- * @example
27
- *
28
- * Basic usage:
29
- *
30
- * ```javascript
31
- * const Koa = require('koa');
32
- * const Router = require('@koa/router');
33
- *
34
- * const app = new Koa();
35
- * const router = new Router();
36
- *
37
- * router.get('/', (ctx, next) => {
38
- * // ctx.router available
39
- * });
40
- *
41
- * app
42
- * .use(router.routes())
43
- * .use(router.allowedMethods());
44
- * ```
45
- *
46
- * @alias module:koa-router
47
- * @param {Object=} opts
48
- * @param {Boolean=false} opts.exclusive only run last matched route's controller when there are multiple matches
49
- * @param {String=} opts.prefix prefix router paths
50
- * @param {String|RegExp=} opts.host host for router match
51
- * @constructor
52
- */
53
- constructor(opts = {}) {
54
- if (!(this instanceof Router)) return new Router(opts); // eslint-disable-line no-constructor-return
55
-
56
- this.opts = opts;
57
- this.methods = this.opts.methods || [
58
- 'HEAD',
59
- 'OPTIONS',
60
- 'GET',
61
- 'PUT',
62
- 'PATCH',
63
- 'POST',
64
- 'DELETE'
65
- ];
66
- this.exclusive = Boolean(this.opts.exclusive);
67
-
68
- this.params = {};
69
- this.stack = [];
70
- this.host = this.opts.host;
71
- }
72
-
73
- /**
74
- * Generate URL from url pattern and given `params`.
75
- *
76
- * @example
77
- *
78
- * ```javascript
79
- * const url = Router.url('/users/:id', {id: 1});
80
- * // => "/users/1"
81
- * ```
82
- *
83
- * @param {String} path url pattern
84
- * @param {Object} params url parameters
85
- * @returns {String}
86
- */
87
- static url(path, ...args) {
88
- return Layer.prototype.url.apply({ path }, args);
89
- }
90
-
91
- /**
92
- * Use given middleware.
93
- *
94
- * Middleware run in the order they are defined by `.use()`. They are invoked
95
- * sequentially, requests start at the first middleware and work their way
96
- * "down" the middleware stack.
97
- *
98
- * @example
99
- *
100
- * ```javascript
101
- * // session middleware will run before authorize
102
- * router
103
- * .use(session())
104
- * .use(authorize());
105
- *
106
- * // use middleware only with given path
107
- * router.use('/users', userAuth());
108
- *
109
- * // or with an array of paths
110
- * router.use(['/users', '/admin'], userAuth());
111
- *
112
- * app.use(router.routes());
113
- * ```
114
- *
115
- * @param {String=} path
116
- * @param {Function} middleware
117
- * @param {Function=} ...
118
- * @returns {Router}
119
- */
120
- use(...middleware) {
121
- const router = this;
122
- let path;
123
-
124
- // support array of paths
125
- if (Array.isArray(middleware[0]) && typeof middleware[0][0] === 'string') {
126
- const arrPaths = middleware[0];
127
- for (const p of arrPaths) {
128
- router.use.apply(router, [p, ...middleware.slice(1)]);
129
- }
130
-
131
- return this;
132
- }
133
-
134
- const hasPath = typeof middleware[0] === 'string';
135
- if (hasPath) path = middleware.shift();
136
-
137
- for (const m of middleware) {
138
- if (m.router) {
139
- const cloneRouter = Object.assign(
140
- Object.create(Router.prototype),
141
- m.router,
142
- {
143
- stack: [...m.router.stack]
144
- }
145
- );
146
-
147
- for (let j = 0; j < cloneRouter.stack.length; j++) {
148
- const nestedLayer = cloneRouter.stack[j];
149
- const cloneLayer = Object.assign(
150
- Object.create(Layer.prototype),
151
- nestedLayer
152
- );
153
-
154
- if (path) cloneLayer.setPrefix(path);
155
- if (router.opts.prefix) cloneLayer.setPrefix(router.opts.prefix);
156
- router.stack.push(cloneLayer);
157
- cloneRouter.stack[j] = cloneLayer;
158
- }
159
-
160
- if (router.params) {
161
- const routerParams = Object.keys(router.params);
162
- for (const key of routerParams) {
163
- cloneRouter.param(key, router.params[key]);
164
- }
165
- }
166
- } else {
167
- const keys = [];
168
- pathToRegexp(router.opts.prefix || '', keys);
169
- const routerPrefixHasParam = Boolean(
170
- router.opts.prefix && keys.length > 0
171
- );
172
- router.register(path || '([^/]*)', [], m, {
173
- end: false,
174
- ignoreCaptures: !hasPath && !routerPrefixHasParam
175
- });
176
- }
177
- }
178
-
179
- return this;
180
- }
181
-
182
- /**
183
- * Set the path prefix for a Router instance that was already initialized.
184
- *
185
- * @example
186
- *
187
- * ```javascript
188
- * router.prefix('/things/:thing_id')
189
- * ```
190
- *
191
- * @param {String} prefix
192
- * @returns {Router}
193
- */
194
- prefix(prefix) {
195
- prefix = prefix.replace(/\/$/, '');
196
-
197
- this.opts.prefix = prefix;
198
-
199
- for (let i = 0; i < this.stack.length; i++) {
200
- const route = this.stack[i];
201
- route.setPrefix(prefix);
202
- }
203
-
204
- return this;
205
- }
206
-
207
- /**
208
- * Returns router middleware which dispatches a route matching the request.
209
- *
210
- * @returns {Function}
211
- */
212
- middleware() {
213
- const router = this;
214
- const dispatch = (ctx, next) => {
215
- debug('%s %s', ctx.method, ctx.path);
216
-
217
- const hostMatched = router.matchHost(ctx.host);
218
-
219
- if (!hostMatched) {
220
- return next();
221
- }
222
-
223
- const path =
224
- router.opts.routerPath ||
225
- ctx.newRouterPath ||
226
- ctx.path ||
227
- ctx.routerPath;
228
- const matched = router.match(path, ctx.method);
229
- if (ctx.matched) {
230
- ctx.matched.push.apply(ctx.matched, matched.path);
231
- } else {
232
- ctx.matched = matched.path;
233
- }
234
-
235
- ctx.router = router;
236
-
237
- if (!matched.route) return next();
238
-
239
- const matchedLayers = matched.pathAndMethod;
240
- const mostSpecificLayer = matchedLayers[matchedLayers.length - 1];
241
- ctx._matchedRoute = mostSpecificLayer.path;
242
- if (mostSpecificLayer.name) {
243
- ctx._matchedRouteName = mostSpecificLayer.name;
244
- }
245
-
246
- const layerChain = (
247
- router.exclusive ? [mostSpecificLayer] : matchedLayers
248
- ).reduce((memo, layer) => {
249
- memo.push((ctx, next) => {
250
- ctx.captures = layer.captures(path, ctx.captures);
251
- ctx.request.params = layer.params(path, ctx.captures, ctx.params);
252
- ctx.params = ctx.request.params;
253
- ctx.routerPath = layer.path;
254
- ctx.routerName = layer.name;
255
- ctx._matchedRoute = layer.path;
256
- if (layer.name) {
257
- ctx._matchedRouteName = layer.name;
258
- }
259
-
260
- return next();
261
- });
262
- return [...memo, ...layer.stack];
263
- }, []);
264
-
265
- return compose(layerChain)(ctx, next);
266
- };
267
-
268
- dispatch.router = this;
269
-
270
- return dispatch;
271
- }
272
-
273
- routes() {
274
- return this.middleware();
275
- }
276
-
277
- /**
278
- * Returns separate middleware for responding to `OPTIONS` requests with
279
- * an `Allow` header containing the allowed methods, as well as responding
280
- * with `405 Method Not Allowed` and `501 Not Implemented` as appropriate.
281
- *
282
- * @example
283
- *
284
- * ```javascript
285
- * const Koa = require('koa');
286
- * const Router = require('@koa/router');
287
- *
288
- * const app = new Koa();
289
- * const router = new Router();
290
- *
291
- * app.use(router.routes());
292
- * app.use(router.allowedMethods());
293
- * ```
294
- *
295
- * **Example with [Boom](https://github.com/hapijs/boom)**
296
- *
297
- * ```javascript
298
- * const Koa = require('koa');
299
- * const Router = require('@koa/router');
300
- * const Boom = require('boom');
301
- *
302
- * const app = new Koa();
303
- * const router = new Router();
304
- *
305
- * app.use(router.routes());
306
- * app.use(router.allowedMethods({
307
- * throw: true,
308
- * notImplemented: () => new Boom.notImplemented(),
309
- * methodNotAllowed: () => new Boom.methodNotAllowed()
310
- * }));
311
- * ```
312
- *
313
- * @param {Object=} options
314
- * @param {Boolean=} options.throw throw error instead of setting status and header
315
- * @param {Function=} options.notImplemented throw the returned value in place of the default NotImplemented error
316
- * @param {Function=} options.methodNotAllowed throw the returned value in place of the default MethodNotAllowed error
317
- * @returns {Function}
318
- */
319
- allowedMethods(options = {}) {
320
- const implemented = this.methods;
321
-
322
- return (ctx, next) => {
323
- return next().then(() => {
324
- const allowed = {};
325
-
326
- if (ctx.matched && (!ctx.status || ctx.status === 404)) {
327
- for (let i = 0; i < ctx.matched.length; i++) {
328
- const route = ctx.matched[i];
329
- for (let j = 0; j < route.methods.length; j++) {
330
- const method = route.methods[j];
331
- allowed[method] = method;
332
- }
333
- }
334
-
335
- const allowedArr = Object.keys(allowed);
336
- if (!implemented.includes(ctx.method)) {
337
- if (options.throw) {
338
- const notImplementedThrowable =
339
- typeof options.notImplemented === 'function'
340
- ? options.notImplemented() // set whatever the user returns from their function
341
- : new HttpError.NotImplemented();
342
-
343
- throw notImplementedThrowable;
344
- } else {
345
- ctx.status = 501;
346
- ctx.set('Allow', allowedArr.join(', '));
347
- }
348
- } else if (allowedArr.length > 0) {
349
- if (ctx.method === 'OPTIONS') {
350
- ctx.status = 200;
351
- ctx.body = '';
352
- ctx.set('Allow', allowedArr.join(', '));
353
- } else if (!allowed[ctx.method]) {
354
- if (options.throw) {
355
- const notAllowedThrowable =
356
- typeof options.methodNotAllowed === 'function'
357
- ? options.methodNotAllowed() // set whatever the user returns from their function
358
- : new HttpError.MethodNotAllowed();
359
-
360
- throw notAllowedThrowable;
361
- } else {
362
- ctx.status = 405;
363
- ctx.set('Allow', allowedArr.join(', '));
364
- }
365
- }
366
- }
367
- }
368
- });
369
- };
370
- }
371
-
372
- /**
373
- * Register route with all methods.
374
- *
375
- * @param {String} name Optional.
376
- * @param {String} path
377
- * @param {Function=} middleware You may also pass multiple middleware.
378
- * @param {Function} callback
379
- * @returns {Router}
380
- */
381
- all(name, path, middleware) {
382
- if (typeof path === 'string') {
383
- middleware = Array.prototype.slice.call(arguments, 2);
384
- } else {
385
- middleware = Array.prototype.slice.call(arguments, 1);
386
- path = name;
387
- name = null;
388
- }
389
-
390
- // Sanity check to ensure we have a viable path candidate (eg: string|regex|non-empty array)
391
- if (
392
- typeof path !== 'string' &&
393
- !(path instanceof RegExp) &&
394
- (!Array.isArray(path) || path.length === 0)
395
- )
396
- throw new Error('You have to provide a path when adding an all handler');
397
-
398
- this.register(path, methods, middleware, { name });
399
-
400
- return this;
401
- }
402
-
403
- /**
404
- * Redirect `source` to `destination` URL with optional 30x status `code`.
405
- *
406
- * Both `source` and `destination` can be route names.
407
- *
408
- * ```javascript
409
- * router.redirect('/login', 'sign-in');
410
- * ```
411
- *
412
- * This is equivalent to:
413
- *
414
- * ```javascript
415
- * router.all('/login', ctx => {
416
- * ctx.redirect('/sign-in');
417
- * ctx.status = 301;
418
- * });
419
- * ```
420
- *
421
- * @param {String} source URL or route name.
422
- * @param {String} destination URL or route name.
423
- * @param {Number=} code HTTP status code (default: 301).
424
- * @returns {Router}
425
- */
426
- redirect(source, destination, code) {
427
- // lookup source route by name
428
- if (typeof source === 'symbol' || source[0] !== '/') {
429
- source = this.url(source);
430
- if (source instanceof Error) throw source;
431
- }
432
-
433
- // lookup destination route by name
434
- if (
435
- typeof destination === 'symbol' ||
436
- (destination[0] !== '/' && !destination.includes('://'))
437
- ) {
438
- destination = this.url(destination);
439
- if (destination instanceof Error) throw destination;
440
- }
441
-
442
- return this.all(source, (ctx) => {
443
- ctx.redirect(destination);
444
- ctx.status = code || 301;
445
- });
446
- }
447
-
448
- /**
449
- * Create and register a route.
450
- *
451
- * @param {String} path Path string.
452
- * @param {Array.<String>} methods Array of HTTP verbs.
453
- * @param {Function} middleware Multiple middleware also accepted.
454
- * @returns {Layer}
455
- * @private
456
- */
457
- register(path, methods, middleware, opts = {}) {
458
- const router = this;
459
- const { stack } = this;
460
-
461
- // support array of paths
462
- if (Array.isArray(path)) {
463
- for (const curPath of path) {
464
- router.register.call(router, curPath, methods, middleware, opts);
465
- }
466
-
467
- return this;
468
- }
469
-
470
- // create route
471
- const route = new Layer(path, methods, middleware, {
472
- end: opts.end === false ? opts.end : true,
473
- name: opts.name,
474
- sensitive: opts.sensitive || this.opts.sensitive || false,
475
- strict: opts.strict || this.opts.strict || false,
476
- prefix: opts.prefix || this.opts.prefix || '',
477
- ignoreCaptures: opts.ignoreCaptures
478
- });
479
-
480
- if (this.opts.prefix) {
481
- route.setPrefix(this.opts.prefix);
482
- }
483
-
484
- // add parameter middleware
485
- for (let i = 0; i < Object.keys(this.params).length; i++) {
486
- const param = Object.keys(this.params)[i];
487
- route.param(param, this.params[param]);
488
- }
489
-
490
- stack.push(route);
491
-
492
- debug('defined route %s %s', route.methods, route.path);
493
-
494
- return route;
495
- }
496
-
497
- /**
498
- * Lookup route with given `name`.
499
- *
500
- * @param {String} name
501
- * @returns {Layer|false}
502
- */
503
- route(name) {
504
- const routes = this.stack;
505
-
506
- for (let len = routes.length, i = 0; i < len; i++) {
507
- if (routes[i].name && routes[i].name === name) return routes[i];
508
- }
509
-
510
- return false;
511
- }
512
-
513
- /**
514
- * Generate URL for route. Takes a route name and map of named `params`.
515
- *
516
- * @example
517
- *
518
- * ```javascript
519
- * router.get('user', '/users/:id', (ctx, next) => {
520
- * // ...
521
- * });
522
- *
523
- * router.url('user', 3);
524
- * // => "/users/3"
525
- *
526
- * router.url('user', { id: 3 });
527
- * // => "/users/3"
528
- *
529
- * router.use((ctx, next) => {
530
- * // redirect to named route
531
- * ctx.redirect(ctx.router.url('sign-in'));
532
- * })
533
- *
534
- * router.url('user', { id: 3 }, { query: { limit: 1 } });
535
- * // => "/users/3?limit=1"
536
- *
537
- * router.url('user', { id: 3 }, { query: "limit=1" });
538
- * // => "/users/3?limit=1"
539
- * ```
540
- *
541
- * @param {String} name route name
542
- * @param {Object} params url parameters
543
- * @param {Object} [options] options parameter
544
- * @param {Object|String} [options.query] query options
545
- * @returns {String|Error}
546
- */
547
- url(name, ...args) {
548
- const route = this.route(name);
549
- if (route) return route.url.apply(route, args);
550
-
551
- return new Error(`No route found for name: ${String(name)}`);
552
- }
553
-
554
- /**
555
- * Match given `path` and return corresponding routes.
556
- *
557
- * @param {String} path
558
- * @param {String} method
559
- * @returns {Object.<path, pathAndMethod>} returns layers that matched path and
560
- * path and method.
561
- * @private
562
- */
563
- match(path, method) {
564
- const layers = this.stack;
565
- let layer;
566
- const matched = {
567
- path: [],
568
- pathAndMethod: [],
569
- route: false
570
- };
571
-
572
- for (let len = layers.length, i = 0; i < len; i++) {
573
- layer = layers[i];
574
-
575
- debug('test %s %s', layer.path, layer.regexp);
576
-
577
- // eslint-disable-next-line unicorn/prefer-regexp-test
578
- if (layer.match(path)) {
579
- matched.path.push(layer);
580
-
581
- if (layer.methods.length === 0 || layer.methods.includes(method)) {
582
- matched.pathAndMethod.push(layer);
583
- if (layer.methods.length > 0) matched.route = true;
584
- }
585
- }
586
- }
587
-
588
- return matched;
589
- }
590
-
591
- /**
592
- * Match given `input` to allowed host
593
- * @param {String} input
594
- * @returns {boolean}
595
- */
596
- matchHost(input) {
597
- const { host } = this;
598
-
599
- if (!host) {
600
- return true;
601
- }
602
-
603
- if (!input) {
604
- return false;
605
- }
606
-
607
- if (typeof host === 'string') {
608
- return input === host;
609
- }
610
-
611
- if (typeof host === 'object' && host instanceof RegExp) {
612
- return host.test(input);
613
- }
614
- }
615
-
616
- /**
617
- * Run middleware for named route parameters. Useful for auto-loading or
618
- * validation.
619
- *
620
- * @example
621
- *
622
- * ```javascript
623
- * router
624
- * .param('user', (id, ctx, next) => {
625
- * ctx.user = users[id];
626
- * if (!ctx.user) return ctx.status = 404;
627
- * return next();
628
- * })
629
- * .get('/users/:user', ctx => {
630
- * ctx.body = ctx.user;
631
- * })
632
- * .get('/users/:user/friends', ctx => {
633
- * return ctx.user.getFriends().then(function(friends) {
634
- * ctx.body = friends;
635
- * });
636
- * })
637
- * // /users/3 => {"id": 3, "name": "Alex"}
638
- * // /users/3/friends => [{"id": 4, "name": "TJ"}]
639
- * ```
640
- *
641
- * @param {String} param
642
- * @param {Function} middleware
643
- * @returns {Router}
644
- */
645
- param(param, middleware) {
646
- this.params[param] = middleware;
647
- for (let i = 0; i < this.stack.length; i++) {
648
- const route = this.stack[i];
649
- route.param(param, middleware);
650
- }
651
-
652
- return this;
653
- }
654
- }
655
-
656
- /**
657
- * Create `router.verb()` methods, where *verb* is one of the HTTP verbs such
658
- * as `router.get()` or `router.post()`.
659
- *
660
- * Match URL patterns to callback functions or controller actions using `router.verb()`,
661
- * where **verb** is one of the HTTP verbs such as `router.get()` or `router.post()`.
662
- *
663
- * Additionally, `router.all()` can be used to match against all methods.
664
- *
665
- * ```javascript
666
- * router
667
- * .get('/', (ctx, next) => {
668
- * ctx.body = 'Hello World!';
669
- * })
670
- * .post('/users', (ctx, next) => {
671
- * // ...
672
- * })
673
- * .put('/users/:id', (ctx, next) => {
674
- * // ...
675
- * })
676
- * .del('/users/:id', (ctx, next) => {
677
- * // ...
678
- * })
679
- * .all('/users/:id', (ctx, next) => {
680
- * // ...
681
- * });
682
- * ```
683
- *
684
- * When a route is matched, its path is available at `ctx._matchedRoute` and if named,
685
- * the name is available at `ctx._matchedRouteName`
686
- *
687
- * Route paths will be translated to regular expressions using
688
- * [path-to-regexp](https://github.com/pillarjs/path-to-regexp).
689
- *
690
- * Query strings will not be considered when matching requests.
691
- *
692
- * #### Named routes
693
- *
694
- * Routes can optionally have names. This allows generation of URLs and easy
695
- * renaming of URLs during development.
696
- *
697
- * ```javascript
698
- * router.get('user', '/users/:id', (ctx, next) => {
699
- * // ...
700
- * });
701
- *
702
- * router.url('user', 3);
703
- * // => "/users/3"
704
- * ```
705
- *
706
- * #### Multiple middleware
707
- *
708
- * Multiple middleware may be given:
709
- *
710
- * ```javascript
711
- * router.get(
712
- * '/users/:id',
713
- * (ctx, next) => {
714
- * return User.findOne(ctx.params.id).then(function(user) {
715
- * ctx.user = user;
716
- * next();
717
- * });
718
- * },
719
- * ctx => {
720
- * console.log(ctx.user);
721
- * // => { id: 17, name: "Alex" }
722
- * }
723
- * );
724
- * ```
725
- *
726
- * ### Nested routers
727
- *
728
- * Nesting routers is supported:
729
- *
730
- * ```javascript
731
- * const forums = new Router();
732
- * const posts = new Router();
733
- *
734
- * posts.get('/', (ctx, next) => {...});
735
- * posts.get('/:pid', (ctx, next) => {...});
736
- * forums.use('/forums/:fid/posts', posts.routes(), posts.allowedMethods());
737
- *
738
- * // responds to "/forums/123/posts" and "/forums/123/posts/123"
739
- * app.use(forums.routes());
740
- * ```
741
- *
742
- * #### Router prefixes
743
- *
744
- * Route paths can be prefixed at the router level:
745
- *
746
- * ```javascript
747
- * const router = new Router({
748
- * prefix: '/users'
749
- * });
750
- *
751
- * router.get('/', ...); // responds to "/users"
752
- * router.get('/:id', ...); // responds to "/users/:id"
753
- * ```
754
- *
755
- * #### URL parameters
756
- *
757
- * Named route parameters are captured and added to `ctx.params`.
758
- *
759
- * ```javascript
760
- * router.get('/:category/:title', (ctx, next) => {
761
- * console.log(ctx.params);
762
- * // => { category: 'programming', title: 'how-to-node' }
763
- * });
764
- * ```
765
- *
766
- * The [path-to-regexp](https://github.com/pillarjs/path-to-regexp) module is
767
- * used to convert paths to regular expressions.
768
- *
769
- *
770
- * ### Match host for each router instance
771
- *
772
- * ```javascript
773
- * const router = new Router({
774
- * host: 'example.domain' // only match if request host exactly equal `example.domain`
775
- * });
776
- *
777
- * ```
778
- *
779
- * OR host cloud be a regexp
780
- *
781
- * ```javascript
782
- * const router = new Router({
783
- * host: /.*\.?example\.domain$/ // all host end with .example.domain would be matched
784
- * });
785
- * ```
786
- *
787
- * @name get|put|post|patch|delete|del
788
- * @memberof module:koa-router.prototype
789
- * @param {String} path
790
- * @param {Function=} middleware route middleware(s)
791
- * @param {Function} callback route callback
792
- * @returns {Router}
793
- */
794
- for (const method of methods) {
795
- Router.prototype[method] = function (name, path, middleware) {
796
- if (typeof path === 'string' || path instanceof RegExp) {
797
- middleware = Array.prototype.slice.call(arguments, 2);
798
- } else {
799
- middleware = Array.prototype.slice.call(arguments, 1);
800
- path = name;
801
- name = null;
802
- }
803
-
804
- // Sanity check to ensure we have a viable path candidate (eg: string|regex|non-empty array)
805
- if (
806
- typeof path !== 'string' &&
807
- !(path instanceof RegExp) &&
808
- (!Array.isArray(path) || path.length === 0)
809
- )
810
- throw new Error(
811
- `You have to provide a path when adding a ${method} handler`
812
- );
813
-
814
- this.register(path, [method], middleware, { name });
815
-
816
- return this;
817
- };
818
- }
819
-
820
- // Alias for `router.delete()` because delete is a reserved word
821
- // eslint-disable-next-line dot-notation
822
- Router.prototype.del = Router.prototype['delete'];
823
-
824
- module.exports = Router;