Is it possible to skip route middleware in node express?
Asked Answered
N

5

11

Take the following POST function in express. (I am using express 3.5.1)

app.post('/example', someFunctionOne, someFunctionTwo, function(req, res){
    if(!req.someVar){
        return res.send(400, { message: 'error'});
    } else{
        return res.json(200, { message: 'ok'}); 
    }
});

If I get some result from someFunctionOne which means someFunctionTwo is redundant, is there a way to skip someFunctionTwo and go to the last unnamed function which will send the response?

So I guess in the same way there is the "next()" function where is the "last()" function? If this is not possible why not? It seems like an oversight to me but is there a good reason?

Neve answered 19/7, 2014 at 12:45 Comment(0)
C
12

You can do next('route') which will go to the next route entirely. This is not exactly what you need in this case, but it would work if you broke your code up into 2 separate routes.

However, I think there are generally 2 approaches to this kind of conditional logic:

  • make someFunctionOne put some state on the req instance when it gets the special result and make someFunctionTwo smart enough to check for that and when found call next() and bypass itself. This is the most idiomatic express thing to do, and it's how most middleware detect when they have been called more than once on the same request and avoid redoing their work again.
  • In someFunctionOne, when the special case happens, just invoke lastFunction directly. Remember the middleware abstraction isn't the holy grail. If your middleware are so tightly coupled, maybe they should be one middleware and some helper functions. There are lots of other ways to organize code that might feel more natural.
Cheney answered 19/7, 2014 at 14:47 Comment(2)
Can you clarify what you mean by next('route'). Do you mean next('/route2'). There doesn't seem to be any documentation on the next route with a parameter. Is it not possible that the parameter could be a function?I am already doing what you suggest in your first bullet. It just seems inefficient/ugly code wise having to attach variables to skip through functions when a 'last()' function would be much neater. I can't do your second suggestion because all the final functions are named functions (which I like because it keeps the function with the request route)Neve
No I mean literally exactly next('route');. 'route' is a magic string connect will recognize.Cheney
S
6

My instinct is to do something like this:

const funcOne = (req, res, next) => {
  // do something
  if (/* you were successful */) {
    res.locals.shouldSkipFuncTwo = true
  }
  next()
}

const funcTwo = (req, res, next) => {
  if (res.locals.shouldSkipFuncTwo) return next()
  // do whatever stuff
  next()
}

router.get('/', funcOne, funcTwo, (req, res) => {
  res.status(200).send('hello world')
)}

If you haven't used res.locals before, here are the express docs on it. Basically, it's a property in the response object that's there for you to use as a container.

Shipwright answered 23/2, 2018 at 21:5 Comment(0)
C
1

Probably the best way to do it to make some helper or put your own middleware into chain instead of your functions.

So your code will look like:

app.post('/example', oneOf(key, someFunctionOne, someFunctionTwo), function(req, res){
  if(!req[key]){
    return res.send(400, { message: 'error'});
  } else{
    return res.json(200, { message: 'ok'}); 
  }
});

And the helper should be something like that:

function oneOf (key) {
  var fns = Array.prototype.slice.call(arguments, 1);
  var l = fns.length;
  return function (req, res, next) {
    var i = 0;
    function _next () {
      if (req[key] || i === l) return next();
      fns[i](req, res, _next);
      i += 1;
    }
    _next();
  }
}

If you will decide to do it just here the code will looks like:

app.post('/example', functionOneOrTwo, function(req, res){
  if(!req.someVar){
    return res.send(400, { message: 'error'});
  } else{
    return res.json(200, { message: 'ok'}); 
  }
});

function functionOneOrTwo(req, res, next) {
  someFunctionOne(req, res, function () {
    if (req.someVar) return next();
    someFunctionTwo(req, res, next);
  });
}

Simple, but untested ;-)

Clemens answered 7/12, 2014 at 1:56 Comment(0)
A
1

Actually I was facing the very same problem. And I just found the express-unless module which does exactly this: https://github.com/jfromaniello/express-unless

Aha answered 7/9, 2016 at 7:4 Comment(0)
P
0

You can skip the middleware logic based on certain condition by adding the conditon inside your middleware function. For Example:

// add local response to every request
app.use('*', (req, res, next) => {
  res.locals._APP = {
    skipToLastMiddleware: false, // directly skip to send response middleware
    response: { error: false, errorCode: 0, message: '', data: {} },
    statusCode: 200
  };
  next();
});

Then you can add to specific or all route to skip the middleware; please look into following code:

router.get('/path', async (req, res, next) => {
  // skip to last/response middleware
  if (res.locals._APP.skipToLastMiddleware) return next();
  
}
Porphyry answered 12/8, 2024 at 11:59 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.