Skip to content

Commit 74d7393

Browse files
authored
Merge pull request davidbanham#12 from kronicker/feature/handle-params
Handle param middleware errors
2 parents d87696c + f2ca1f2 commit 74d7393

File tree

3 files changed

+54
-38
lines changed

3 files changed

+54
-38
lines changed

index.js

+23-29
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,36 @@
11
const Layer = require('express/lib/router/layer');
2+
const Router = require('express/lib/router');
23

3-
function copyOldProps(oldFn, newFn) {
4+
const last = (arr = []) => arr[arr.length - 1];
5+
const noop = Function.prototype;
6+
7+
function copyFnProps(oldFn, newFn) {
48
Object.keys(oldFn).forEach((key) => {
59
newFn[key] = oldFn[key];
610
});
711
return newFn;
812
}
913

10-
function wrapErrorMiddleware(fn) {
11-
const newFn = (err, req, res, next) => {
12-
const ret = fn.call(this, err, req, res, next);
13-
14-
if (ret && ret.catch) {
15-
ret.catch(innerErr => next(innerErr));
16-
}
17-
14+
function wrap(fn) {
15+
const newFn = function newFn(...args) {
16+
const ret = fn.apply(this, args);
17+
const next = (args.length === 5 ? args[2] : last(args)) || noop;
18+
if (ret && ret.catch) ret.catch(err => next(err));
1819
return ret;
1920
};
20-
return copyOldProps(fn, newFn);
21+
Object.defineProperty(newFn, 'length', {
22+
value: fn.length,
23+
writable: false,
24+
});
25+
return copyFnProps(fn, newFn);
2126
}
2227

23-
function wrap(fn) {
24-
const newFn = (req, res, next) => {
25-
const ret = fn.call(this, req, res, next);
26-
27-
if (ret && ret.catch) {
28-
ret.catch((err) => {
29-
next(err);
30-
});
31-
}
32-
33-
return ret;
28+
function patchRouterParam() {
29+
const originalParam = Router.prototype.constructor.param;
30+
Router.prototype.constructor.param = function param(name, fn) {
31+
fn = wrap(fn);
32+
return originalParam.call(this, name, fn);
3433
};
35-
return copyOldProps(fn, newFn);
3634
}
3735

3836
Object.defineProperty(Layer.prototype, 'handle', {
@@ -41,13 +39,9 @@ Object.defineProperty(Layer.prototype, 'handle', {
4139
return this.__handle;
4240
},
4341
set(fn) {
44-
// Bizarre, but Express checks for 4 args to detect error middleware: https://github.com/expressjs/express/blob/master/lib/router/layer.js
45-
if (fn.length === 4) {
46-
fn = wrapErrorMiddleware(fn);
47-
} else {
48-
fn = wrap(fn);
49-
}
50-
42+
fn = wrap(fn);
5143
this.__handle = fn;
5244
},
5345
});
46+
47+
patchRouterParam();

package-lock.json

+9-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test.js

+22
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,28 @@ describe('express-async-errors', () => {
6363
.expect(495);
6464
});
6565

66+
it('and propagates param middleware errors too', () => {
67+
const app = express();
68+
69+
app.param('id', async () => {
70+
throw new Error('error');
71+
});
72+
73+
app.get('/test/:id', async (err, req, next, id) => {
74+
console.log(id);
75+
throw new Error('error');
76+
});
77+
78+
app.use((err, req, res, next) => {
79+
res.status(495);
80+
res.end();
81+
});
82+
83+
return supertest(app)
84+
.get('/test/12')
85+
.expect(495);
86+
});
87+
6688
it('should preserve the router stack for external routes', () => {
6789
const app = express();
6890

0 commit comments

Comments
 (0)