Express.js - wrap every middleware/route in "decorator"

Viewed 4333

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.

3 Answers

You could wrap middleware and router as below

function wrapper(func) {
    return function inner(req, res, next) {
        const start = Date.now();
        func(req, res, function () {
            let elapsedMS = Date.now() - start
            console.log('time elapsed for function ' + func.prototype.constructor.name + ' is ' + elapsedMS)

            next.apply(this, arguments);
        });
    };
}


var originalAppUse = app.use;
app.use = function () {
    lastArg = arguments.length - 1;

    if (typeof arguments[lastArg] === 'function') {
        arguments[lastArg] = wrapper(arguments[lastArg])
    }

    originalAppUse.apply(this, arguments)
}
Related