Express Middleware, Next and Promises

There is a very simple Express router with a handler:

router.get('/users/:userId/roles/:roleId', function(req, res, next){ const roleId = req.params.roleId; res.rest.resource = UserModel.findOne({ _id: req.params.userId}).exec().then(function(usr) { console.log(req.params.roleId); // => undefined console.log(roleId); // => okay here const result = usr.roles.find( role => String(role._id) === String(roleId)); return result; }); next(); }); 

As you can see, access to req.params.roleId as part of the promise returns undefined . This is true only when next() is called an external then promise.

I agree with asyncing and promises and understand that next() will be called before the handler in then . But what happens with req.params.roleId ? Why and where does it mutate? Does middleware called next() get the same but mutated req ?

Note: res.rest.resource used by middleware, later called a REST response.

+5
source share
1 answer

Code, like it, is vague in its execution.

Something mutates the role identifier in the next() handler, and since it takes some time for findOne() to send to the then handler, this mutation has already occurred.

Without knowing any additional information about your application, it looks like this might be the correct implementation.

 router.get('/users/:userId/roles/:roleId', function(req, res, next) { const roleId = req.params.roleId; UserModel.findOne({ _id: req.params.userId}).exec().then((usr) => { const result = usr.roles.find(role => String(role._id) === String(roleId)); res.rest.resource = result; next(); // <-- only dispatch to next after we find the resource result }); }); 

Edit:

I dug a little deeper. Check out this little app:

 var express = require('express'); var app = express(); app.use(function (req, res, next) { var v = 0 | +new Date(); console.log("middleware 1 setting foos to ", v); req.params.foo = v; req.foo = v; next(); }); app.use(function (req, res, next) { console.log("middleware 2 reading foos and starting timer:", req.params.foo, req.foo); setTimeout(function() { console.log("middleware 2: foos are now", req.params.foo, req.foo); }, 1000); next(); }); app.get("/", function(req, res) { res.send("params = " + JSON.stringify(req.params) + " and foo = " + req.foo); }); app.listen(3000); 

Query Request

 middleware 1 setting foos to -902674369 middleware 2 reading foos and starting timer: undefined -902674369 middleware 2: foos are now undefined -902674369 middleware 1 setting foos to -902673113 middleware 2 reading foos and starting timer: undefined -902673113 middleware 2: foos are now undefined -902673113 

and the browser output is params = {} and foo = -902673113 , so it turns out that you are not allowed to touch req.params , but you can add any other properties to the req object and they will travel well.

This seems to be due to the fact that the rewriting of the params layer is performed at each step.

+3
source

Source: https://habr.com/ru/post/1242633/


All Articles