I have Express.js instance and couple of routes which I want to wrap in some function. Example:
const wrapper = (route) => { return (req, res, next) => { let result = route(req, res, next); // do some independent processing } }; app.get('/', wrapper((req, res, next) => { // respond to request somehow }));
While this works fine, I don’t like the idea to explicitly call wrapper
on every route or middleware which requires such processing.
Is there any way to be able to wrap every required route/middleware in certain wrapper (given that wrapper
function can check that this route/middleware needs to be wrapped) implicitly (via Express.js
extension, monkey-patching or some special middleware)?
UPDATE:
More solid example. Let’s assume I want to make an async
router functions. But I don’t want to catch errors in each and every route function. So I wrap them up:
const wrapper = func => (req, res, next) => { const promise = func(req, res, next); if (promise.catch) { promise.catch(err => next(err)); } next(); }; app.get('/one', wrapper(async (req, res, next) => { // respond to request somehow })); app.get('/two', wrapper(async (req, res, next) => { // respond to request somehow })); app.get('/three', wrapper(async (req, res, next) => { // respond to request somehow })); // and so on... app.use((err, req, res, next) => { // do something with intercepted error });
This explicit wrapper
around all routes is actually the thing I want to get rid of.
Advertisement
Answer
It turned out to be a bit of a PITA because, ultimately, Express doesn’t propagate the return value of a route handler function.
This is what I came up with (a monkey-patch):
const Layer = require('express/lib/router/layer'); const handle_request = Layer.prototype.handle_request; Layer.prototype.handle_request = function(req, res, next) { if (! this.isWrapped && this.method) { let handle = this.handle; this.handle = function(req, res, next) { // this is basically your wrapper let result = handle.apply(this, arguments); // do some independent processing return result; }; this.isWrapped = true; } return handle_request.apply(this, arguments); };
I would probably suggest using a similar approach as express-promise-router
though, which implements a drop-in replacement for Express’ Router
. However, it’s not implicit.