I was trying to use two Express param
functions in one route, and one of the param functions needed the other param to be loaded. For example, if I have the route file:
// route file
app.route('/api/v1/toolboxes/:toolboxId/tools/:toolId')
...
app.param('toolboxId', controller.loadToolbox);
...
app.param('toolId', controller.loadToolAndEnsureFromToolbox);
And an associated controller:
exports.loadToolbox = function(req, res, next, id) {
// load toolbox from Mongoose into req.toolbox
req.toolbox.maker = req.toolbox.maker || 'Stanley';
};
// controller
exports.loadToolAndEnsureFromToolbox = function(req, res, next, id) {
Tool.findAsync({
_id: id,
}).then(function(tool) {
if (!tool) {
res.status(404).send("Tool not found");
} else if (tool.maker !== req.toolbox.maker) { // <<<<<
res.status(403).send("This tool isn't from the right maker!");
} else {
req.tool = tool;
...
next();
}
});
...
};
I wasn’t positive that toolbox
would always be loaded when I wanted to check it in tool
. (This is kind of a strange example, but it resembles a problem that I was trying to solve.)
The tricky thing was that the different param
calls were coming from different route files, so I wasn’t sure if this would affect the results either.
My mental model was: params get resolved in some order, then middleware runs, then the controller runs. If anything in the chain sends a response or does not call next with a non-error, then execution stops. So another way of loading the params in a deterministic way would be to have one middleware that loads both in a specific order. This seemed undesirable since it was extra code and I already had some working param
functions.
I tried searching online for a solution, but didn’t see anything that clarified what order the params load in.
I asked about the problem in our internal Slack #dev channel.
Craig wrote back:
I wouldn’t be surprised if it was left to right, or if it was the order of the params being registered, if it acts like other parts of express.
Some other parts of Express would be middleware if used in router.use()
.
Experiment
I wanted to experiment to figure out whether the params were deterministic, and if so, what the rules were.
Experimentation showed: app.param(...)
calls are resolved in the order that you put the param in the route. Params get resolved left to right (as you read). I figured this out by seeing which order the calls were done in and then reversing the parameters. It does not appear to matter what order the params are declared in your routes files (I switched these around as well, with no effect.)
This is nice because it:
1. is deterministic
2. is fairly logical
3. saves me from having to add in a middleware or an app.all
for a route when this should be handled with param