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!