If you tried or happened to throw an error from within an async express route handler then you are probably looking at an error that looks like this:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with.catch(). (rejection id: 1)
[DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Trying to find the cleanest solution to this has led me to quite a few places that offer the following solutions:
- Wrapping all request handler logic in
try
/catch
blocks to pass the caught error to thenext()
function - Wrapping every request handler inside a function that checks if the handler is an async function to further wrap it with a
.catch(next)
.
You can see both of these explained here: https://zellwk.com/blog/async-await-express/. These are both viable solutions. Though, I wanted to seek out a way to do this passively instead of actively.
This is what led me to utilize JavaScript's native Proxy
built-in:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
Used in tandem with the handler.apply()
method, explained here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/apply.
Below is a singular simple patch to fix this issue, without having to do anything with each async request handler.
const Layer = require('express/lib/router/layer')
Object.defineProperty(Layer.prototype, 'handle', {
set: function (handle) {
this._handle = new Proxy(handle, {
apply: function (target, thisArg, argumentsList) {
const type = target.constructor.name
if (type === 'AsyncFunction') {
const wrappedFunction = (...args) => {
const next = args[args.length - 1] || Function.prototype
target.apply(thisArg, args).catch(next)
}
wrappedFunction(...argumentsList)
return
}
target.apply(thisArg, argumentsList)
return
}
})
},
get: function () {
return this._handle
}
})
Import or run this piece of code upon server startup and it will patch express.
There is a very similar version of this here https://github.com/davidbanham/express-async-errors/blob/master/index.js as well.
Let me know your thoughts in the comments below!
Top comments (0)