I am having trouble understanding the use of await
in Node with mongoose and express.
Basically I have a page /profile
where I generate a token for every get request I have, according to the user that is connected:
router.get('/profile', requiresLogin, (req, res, next) => {
User.findById(req.session.userId).exec(function(err, user){
if(err || !user){
//Display error and return
return res.send("Error");
}
var token = Token.generateToken(user);
console.log("Token is: " token);
return res.send("Working");
}
})
The function to generate the token is the following:
TokenSchema.statics.generateToken = function(user){
const newToken = new this({
_userId: user._id,
token: crypto.randomBytes(16).toString('hex')
});
await newToken.save();
return newToken;
}
And I get an error on the await
line saying: SyntaxError: await is only valid in async functions and the top level bodies of modules
.
I think the code is quite intuitive, so what I want to accomplish is to have an static function to generate the Token
objects. Then this function will return and other methods (like the one I posted that gets executed when getting /profile
) can use it to create new tokens.
Is this the proper way to achieve what I am trying to achieve? I would like recommendations on how to do this code more "nodejs", since I am used to other languages where there are no promises and so on, and this is the best I could come up with. I know it is possible to do with callbacks and so on, but I think they might complicate the code for what it should be with other languages.
Thanks!
UPDATE: just after posting I saw that removing the await
does what I expected, but as I have seen in here:
The save() method is asynchronous, so it returns a promise that you can await on.
So I don't really understand how nor why it is working
CodePudding user response:
You can't use await
in a non-async funciton, which means that:
generateToken
must beasync
.- When calling
generateToken
in the request handler, you must alsoawait
that call. - Again, you can't use
await
there without marking the anonymous handler function asasync
.
Your handler should look like this:
router.get("/profile", requiresLogin, (req, res, next) => {
User.findById(req.session.userId).exec(async (err, user) => {
if(err || !user) {
return res.send("Error");
}
const token = await Token.generateToken(user);
console.log("Token is: " token);
return res.send("Working");
});
});
And the token generation function:
TokenSchema.statics.generateToken = async function(user) {
const newToken = new this({
_userId: user._id,
token: crypto.randomBytes(16).toString('hex')
});
await newToken.save();
return newToken;
}
You can also use async/await
with Mongoose (instead of using callbacks), so your handler could look like this:
router.get("/profile", requiresLogin, async (req, res, next) => {
try {
const user = await User.findById(req.session.userId).exec();
if (!user) return res.send("Can't find user.");
const token = await Token.generateToken(user);
console.log("Token is: " token);
return res.send("Working");
} catch (err) {
return res.send("Error.");
}
});