Node.js/Express

Router Parameters

WebDevLee 2021. 11. 18. 19:54

이 글은 Express의 Router Parameters에 관한 심화 내용을 정리하였습니다.




< Introduction >

When building interfaces with Express, we will run into the pattern of expecting certain information in a requested URL and using that information to identify the data that is being requested.
To give an example :
app.get('/sorcerers/:sorcererName', (req, res, next) => {
  const sorcerer = Sorcerers[req.params.sorcererName];
  res.send(sorcerer.info);
});
 
app.get('/sorcerers/:sorcererName/spellhistory', (req, res, next) => {
  const sorcerer = Sorcerers[req.params.sorcererName];
  const spellHistory = Spells[sorcerer.id].history;
  res.send(spellHistory);
});​

In the above code we need to extract the request parameter ' :sorcererName ' from the url in both instances, and end up duplicating the necessary code so that it appears in both routes.

-> Here are some ways to avoid this duplication and write more quality code!

 

 


< router.param( ) >

To avoid replicated parameter-matching code, use router.param( ) method.

 

< router.param( ) method >

1. router.param( )  intercept any request
to a route handler with the first argument.
2. in the app.param function signature, the first argument does not have the leading :
3. The actual value will be passed in as the fourth argument in the middleware.

ex)

app.param('spellId', (req, res, next, id) => {
  let spellId = Number(id);
    try {
      const found = SpellBook.find((spell) => {
        return spellId === spell.id;
      })
      if (found) {
        req.spell = found;
        next();
      } else {
        next(new Error('Your magic spell was not found in any of our tomes'));
      };
    } catch (err) {
      next(err)
    }
});

 

1. 'spellId' does not have the leading :
2. The actual ID will be passed in as the middleware's fourth argument, id in this case, to the app.param callback function when a request arrives.

-> Note that inside an app.param callback, you should use the fourth argument as the parameter’s value, not a key from the req.params object.

 

< example in practice! >

1. Not use router.param( ) method

app.get('/spices/:spiceId', (req, res, next) => {
  const spiceId = Number(req.params.id);
  const spiceIndex = spiceRack.findIndex(spice => spice.id === spiceId);
  if (spiceIndex !== -1) {
    res.send(spiceRack[spiceIndex]);
  } else {
    res.status(404).send('Spice not found.');
  }
});

app.put('/spices/:spiceId', (req, res, next) => {
  const spiceId = Number(req.params.id);
  const spiceIndex = spiceRack.findIndex(spice => spice.id === spiceId);
  if (spiceIndex !== -1) {
    spiceRack[spiceIndex] = req.body.spice;
    res.send(spiceRack[spiceIndex]);
  } else {
    res.status(404).send('Spice not found.');
  }
});

2. use router.param( ) method

app.param('spiceId', (req, res, next, id) => {
  let spiceId = Number(id);
  const found = spiceRack.findIndex(e => e.id === spiceId)
  if (found !== -1) {
    req.spiceIndex = found;
    next();
  } else {
    res.status(404);
  }
})

app.get('/spices/:spiceId', (req, res, next) => {
  const spiceIndex = req.spiceIndex;
  res.send(spiceRack[spiceIndex]);
});

app.put('/spices/:spiceId', (req, res, next) => {
  const spiceIndex = req.spiceIndex;
  spiceRack[spiceIndex] = req.body.spice;
  res.send(spiceRack[spiceIndex]);
});

 

 


< Merge Parameters >

When we’re building web endpoints, we might want to access some property of a complex object.
In order to do this in Express, we can design a nested router.


 

  • In order to pass parameters the parent router has access to, we pass a special configuration object when defining the router.
    {mergeParams: true}

ex)

const sorcererRouter = express.Router();
const familiarRouter = express.Router({mergeParams: true});
 
app.use('/sorcerer', sorcererRouter);
sorcererRouter.use('/:sorcererId/familiars', familiarRouter);
 
sorcererRouter.get('/', (req, res, next) => {
  res.status(200).send(Sorcerers);
  next();
});
 
sorcererRouter.param('sorcererId', (req, res, next, id) => {
  const sorcerer = getSorcererById(id);   
  req.sorcerer = sorcerer;
  next();
});
 
familiarRouter.get('/', (req, res, next) => {
  res.status(200).send(`Sorcerer ${req.sorcerer} has familiars ${getFamiliars(sorcerer)}`);
});

: in the above code, familiarRouter can access the parant(sorcererRouter)'s param!