3

At my website.com/v2/bridge/:locationId/process endpoint, the incoming req.body looks like this:

{
  choice: 'a',
  data: [
    {
      ...
    },
    ...
  ]
}

I want to access a particular route depending on what the value of req.body.choice is. If req.body.choice === 'a' then I want to go on to website.com/v2/bridge/:locationId/process/choiceA with the same req being passed on.

I don't know what middleware I need to use to accomplish that. I don't know if that is even possible.

My extremely simplified routes:

// website.com/v2/bridge
const proc = require('./process');

router.use('/:locationId/process', proc);

module.exports = router;




// website.com/v2/bridge/56/process
router.use(function (req, res, next) {
  // ?????????????????????????

  next();
});

const choiceA = require('./choice-a');
const choiceB = require('./choice-b');

router.use('/choice-a', choiceA);
router.use('/choice-b', choiceB);

module.exports = router;





// website.com/v2/bridge/56/process/choice-a
router.post('/', function (req, res) {
  res.send('I got here.');

  return;
});

module.exports = router;

What middleware function do I need to include to conditionally route my request? I am trying to avoid one giant function with if statements that process different things according to the value of req.body.choice.

Jacob
  • 1,302
  • 4
  • 17
  • 38

2 Answers2

4

This will be little trickier for you...give it a try

router.use(function (req, res, next) {
  req.path = "/" + "choice-"+req.body.choice
  req.url = "/" + "choice-"+req.body.choice
  next();
});

now it'will do the request to the end point you want

Dinesh Agrawal
  • 320
  • 1
  • 3
3

As part of finding the answer for the same question, I came across with this question, which didn't settle my mind by messing with the req.url, so here's how I got it done (I know it's a long delay, but better late than never):

When you're dealing with routers, and you want to make a condition to decide whether to use, you can do it with two ways (according to expressjs doc), and let's learn them by examples

1. Skipping between routes

function skipThisRouteMiddleware (req, res, next) {
    if (true === isAmazingValidation) {
        return next('route');
    }

    return next();
}

router.get('/user/:id',
    skipThisRouteMiddleware,
    getUserV1 // TBD - your old route
)

router.get('/user/:id',
    getUserV2 // TBD - your new route
)

In the case above, when you have two routes, and you want to conditionally pick one of them, it can be done by specifying a middleware that makes the validation for the first route only, and when needed, it triggers next('route') which skip to the next matching route, please note that you must specify METHOD and not generally app.use()

2. Skipping between routers

// routers/index.js
const mainRouter = express.Router();
mainRouter.use(oldRouter);
mainRouter.use(newRouter);


// routers/old.js
const oldRouter = express.Router();

function canUpgradeToNewRouter (req, res, next) {
    if (true === isAmazingValidation) {
        return next('router'); // now it's 'router' and not 'route'
    }

    return next();
}

oldRouter.use(canUpgradeToNewRouter);


// routers/new.js
const newRouter = express.Router();

newRouter.use(...);

In this case, you have two different routers, and you want to conditionally pick one of them. for this case, you'll have to create a parent router (mainRouter) and two nested routers (oldRouter, newRouter). The trick here is that the oldRouter tries to run a middleware validation that tries to "upgrade" the requester to the new shiny router, if the condition is true, it will skip the whole oldRouter, and pass the stick to the parent router mainRouter to continue matching routes to this request (the magic - next('router')), which eventually pick the upcoming newRouter

In both methods, we let the first route to make the logic and choose between itself and the others, that's a different perception (a bit)

molaga
  • 130
  • 1
  • 8
  • This seems more viable, would try it out for my project and get back to you, I have been having a problem like this – saas_joel Nov 14 '20 at 17:02
  • What exactly is ```next('router') ```, can that name be changed or is it a standard? For me, I am changing between 3 routers, and they are all separate files. Hence the first two routes will have the switching logic in them. But I need to know exactly what to pass in the first call to ```next()```, must it be ```next('router')``` , or the name of the router file – saas_joel Nov 14 '20 at 22:38
  • 1
    @Alara_stealth the `router` is a constant, just like the `route`. in your case, it doesn't matter what is the file structure but the `app.use()` order (each `next('router')` will bump to the next "use") regardless of the name of the files. unfortunately, it seems like they're not supporting named routes and jumping to them – molaga Nov 16 '20 at 08:05
  • Hence we have to follow a syntactical order? I hope with time it can also be passed directly to the route names – saas_joel Nov 17 '20 at 00:06
  • Slight headache here @molaga The logic I am basing my conditional on rests in a mongo DB collection ```(if the user. status === 'teacher')```. Obviously, this is a DB call and has to be done asynchronously. I am trying to figure out how to first get this criteria declared, so I can easily reference it. – saas_joel Nov 17 '20 at 01:52
  • async function shouldRouterChange(req, res, next) { try { let userRole = await studentProfile.findOne({status:req.user.role}); // conditional if (userRole==='teacher') { return next('router') } ......... I get this error : Cannot read property 'role' of undefined – saas_joel Nov 17 '20 at 03:21
  • Was finally able to implement this, it switches to the next router alright, but then I repeat the middleware function in the second router too, so there could be a switch to a third router if the new condition passes, but this did not work, it goes back to the first router – saas_joel Nov 20 '20 at 15:07