For learning Node.js I follow a course where they use a async/await like this:
exports.signup = async (req, res) => {
const userExists = await userExists.findOne({ email: req.body.email });
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = await new User(req.body);
await user.save();
return res.status(200).json({ user });
}
};
But it gives me a UnhandledPromiseRejectionWarning with crashing the application.
(node:10780) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise
which was not handled with .catch(). (rejection id: 1)
(node:10780) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero
exit code.
It seems I didn't handle the error part but I did it with my else block, isn't it working like this?
Any help will be appreciated.
You need to catch any rejected promise from await statements by surrounding it with try/catch.
exports.signup = async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email });
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = new User(req.body);
await user.save();
return res.status(200).json({ user });
}
} catch(e) {
// some sort of internal error (probably database issue)
console.log(e);
res.sendStatus(500);
}
};
This also removes the await in await new User(req.body) as await only does something useful when you await a promise and new User() is not asynchronous and does not return a promise so there's no reason to use await with it.
Note, that to avoid a race condition where two separate requests might both find that the user doesn't exist and both requests may try to create one, you need to make sure that your user email is configured in the database as a unique key so you can never get duplicate users for the same email. This is a subtlety in server programming that is important to understand to avoid race conditions.
As #jfriend00 said You need to catch any rejected promise from await statements by surrounding it with try/catch. You get ReferenceError because of using userExists before it creates. I am pretty sure that it should be User as you named your Schema User const user = new User(req.body); Let me know if you have any issue after change the code:
exports.signup = async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email }); //I changed it to the Schema name
if (userExists) {
return res.status(403).json({
error: "Email is taken!"
});
} else {
const user = new User(req.body);
await user.save();
return res.status(200).json({ user });
}
} catch(e) {
// some sort of internal error (probably database issue)
console.log(e);
res.sendStatus(500);
}
};
Related
I am trying to reproduce this code using async/await but I can't figure how to
.then.catch chain/nest
exports.signup = (req, res, next) => {
bcrypt.hash(req.body.password, 10)
.then(hash => {
const user = new User({
email: req.body.email,
password: hash
});
user.save()
.then(() => res.status(201).json({ message: 'Utilisateur créé !' }))
.catch(error => res.status(400).json({ error }));
})
.catch(error => res.status(500).json({ error }));
};
What I came up with trying to use async/await
exports.signup = async (req, res, next) => {
try {
const hash = await bcrypt.hash(req.body.password, 10);
const user = new User({
email: req.body.email,
password: hash
});
console.log(user);
let saveUser = await user.save();
console.log(saveUser);
res.status(201).json({ message: 'Utilisateur créé !'})
} catch (e) {
res.status(500).json({e})
}
};
I am getting the user in my console but the code crashes during user.save() since I don't get anything from console.log(saveUser)
I've been reading that you can stack await functions into one try block, but maybe here it doesn't work since you need
I've tried separating the try/catch, requiring me to initialise hash outside of the try block since i'll be using it in the second try but it's also not working.
After editing according to Nil Alfasir's thoughts:
exports.signup = async (req, res, next) => {
try {
const hash = await bcrypt.hash(req.body.password, 10);
const user = new User({
email: req.body.email,
password: hash
});
console.log(user);
user.save();
return res.status(201).json({ message: 'Utilisateur créé !'})
} catch (e) {
return res.status(500).json({e})
}
};
But I'm getting this in the console
(node:43390) UnhandledPromiseRejectionWarning: MongoError: E11000 duplicate key error collection: myFirstDatabase.users index: username_1 dup key: { username: null }
.
.
.
(node:43390) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:43390) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Correcting Nir Alfasi on save async
save() IS a async function SAVE ASYNC
so it won't return anything.
If there's an error it can be caught be catch.
A few issues:
user.save() doesn't return any value (according to the first snippet) - and you're trying to save a returned value into saveUser
Nit: please add a return before res.status...
UPDATE
The "update" of the question totally changed it, please avoid from doing that and post a new question in the future.
Sounds like you must provide a username when creating a user because username must be unique, and when you try to create multiple users without a username the DB creates a record with username=null so the first one may create but the second one will fail.
I was trying to follow up this "Build A Node.js API Authentication With JWT Tutorial" on YouTube. For some reason the post request of /register, is giving me this error:
UnhandledPromiseRejectionWarning: Error: Illegal arguments: undefined, string.
Below you can find the code:
const router = require('express').Router();
const User = require('../user');
const {resigerValidate} = require('../validation');
const bcrypt = require('bcryptjs')
router.post('/register', async (req, res)=>{
// doing validation from validation.js
const {error} = resigerValidate(req.body);
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt);
if (error) {
return res.status(400).send(error.details[0].message);
}
// checks if the email already exists in the database (partially working)
const emailExists = await User.findOne({email: req.body.email});
if (emailExists){
return res.status(400).send('This email already exists in the database !!!');
}
// user creation
const user = new User({
name: req.body.name,
email: req.body.email,
password: hashedPassword
});
try{
const savedUser = await user.save();
res.send(savedUser);
}catch(err){
res.status(400).send(err);
}
});
module.exports = router;
// Error
(node:15748) UnhandledPromiseRejectionWarning: Error: Illegal arguments: undefined, string
at _async (C:\Users\Admin\JavaScript\jwt\jwt\node_modules\bcryptjs\dist\bcrypt.js:214:46)
at C:\Users\Admin\JavaScript\jwt\jwt\node_modules\bcryptjs\dist\bcrypt.js:223:17
at new Promise (<anonymous>)
at Object.bcrypt.hash (C:\Users\Admin\JavaScript\jwt\jwt\node_modules\bcryptjs\dist\bcrypt.js:222:20)
at C:\Users\Admin\JavaScript\jwt\jwt\routes\auth.js:19:41
(node:15748) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:15748) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate
the Node.js process with a non-zero exit code.
According to your stack info bcrypt.hash(..) is rejected. Looks like you need to move this part of the code a little bit lower. Something like
const {error} = resigerValidate(req.body);
// checks if the email already exists in the database (partially working)
const emailExists = await User.findOne({email: req.body.email});
if (emailExists){
return res.status(400).send('This email already exists in the database !!!');
}
try{
// user creation
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt);
if (error) {
return res.status(400).send(error.details[0].message);
}
const user = new User({
name: req.body.name,
email: req.body.email,
password: hashedPassword
});
const savedUser = await user.save();
res.send(savedUser);
}catch(err){
res.status(400).send(err);
}
Good day developers im trying to trigger a process of login for users in my app, generating a token for security reasons, but for some situation im receiving this error
(node:11088) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async
function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:11088) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
despite of allowing the user to log, but then the token although is created isn't exposed on the login json i generated for app purposes checked from my postman.
Lets say i do start the process first in my folder of token generator, after install jsonwebtoken package
jsonwebtoken generation folder
const jsonwebToken = require("jsonwebtoken");
const generateToken =async (userId) => {
return new Promise((reject, resolve) => {
const tokenPayload = { userId };
jsonwebToken.sign(
tokenPayload,
process.env.TOKEN_SECRET_WORD,
{
expiresIn: "12h",
},
(error, generatedToken) => {
if (error) {
reject("cant generate token");
} else {
resolve(generatedToken);
}
}
);
});
};
module.exports = { generateToken };
Once the process of generate the token is set , on my controller for the loginUser function , i set this
et User = require("../modelos/UserModel");
const { response } = require("express");
const cryptoPass = require("bcryptjs");
const { generateToken } = require("../jsonwebtoken/jsonWebTokenGenerator");//path to the json generator
const loginUser = async (request, response = response) => {
const { userEmail, userPassword } = request.body;
try {
const userInDb = await User.findOne({ userEmail });
if (!userInDb) {
return response.status(400).json({
ok: false,
message: "Not user Found",
});
}
const passwordValid = await cryptoPass.compareSync(
userPassword,
userInDb.userPassword
);
if (!passwordValid) {
return response.status(400).json({
ok: false,
message: "Error in Password",
});
}
const tokenGenerated = generateToken(userInDb.id);//generating the tooken in the process
//in order to add it to the user logged json
//once the response is ok(200)
response.status(200).json({
ok: true,
message: "User Logged",
tokenGenerated,//no token
});
} catch (error) {
response.status(500).json({
ok: false,
message: "Some error happened in login",
});
}
};
module.exports = {
loginUser,
};
But then despite of loggin the user , the token isn't brought in the response and that error shows up:
Is weird but if i use an await when asigning the user id to the method of generate token , and then i trigger all the process, then the login isn't successful, and console loggin the catch of that error brings me the token in fact:
......
const tokenGenerated =await generateToken(userInDb.id);//adding an await
// console.log(tokenGenerated,"controller token");
// console.log(userInDb);
response.status(200).json({
ok: true,
message: "User Logged",
tokenGenerated,
});
} catch (error) {
console.log(error,"Error");//loggin the error in the catch
response.status(500).json({
ok: false,
message: "Some error happened in login",
});
}
and in postman the not successful login
Would be amazing any help on this . Thanks in advance!!
The signature of the callback in new Promise() within generateToken is wrong
You are using
return new Promise((reject, resolve) => {
...
});
but the correct one is
return new Promise((resolve, reject) => {
...
});
ie, you switched the resolve and reject parameter. Thus when in your method you try to call resolve(generatedToken); you are actually rejecting your promise with an error of the generated token.
During the course of testing if my user's registration route is working fine using postman as a testing machine, it throw an error that I don't know what it means.
I have tried using an async function to catch the error, but it didn't work out
const express = require('express');
const router = express.Router();
// Use to help set a default image for users
const gravatar = require('gravatar');
// Use to encrypt our password from bringing plain text
const bcrypt = require('bcryptjs');
// I add the user model from my model
// So i can be able to check create a new registration
// and also check if email exist
const User = require('../../models/User');
// #route GET api/users/register
// #desc Register user
// #access Public
router.post('/register', (req, res) => {
User.findOne({ email: req.body.email }).then(user => {
if (user) {
errors.email = 'Email already exists';
return res.status(400).json(errors);
} else {
const avatar = gravatar.url(req.body.email, {
s: '200', // Size
r: 'pg', // Rating
d: 'mm' // Default
});
const newUser = new User({
name: req.body.name,
email: req.body.email,
avatar,
password: req.body.password
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => res.json(user))
.catch(err => console.log(err));
});
});
}
});
});
module.exports = router;
I want the user input on postman should be able to post the form so I can know if the route is actually working fine. And this is the error I got on my console
(node:14164) UnhandledPromiseRejectionWarning: ReferenceError: errors is not defined
at User.findOne.then.user (the working director/name.js:26:7)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:14164) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14164) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Normally we should handle the error in a kind of this way:
User.findOne({ email: req.body.email }).then(user => {
// ...
}).catch(error => {
console.log('error', error)
res.json({error: error})
})
Need a little help. Been learning NodeJS. And so far so good. But I am running into an issue when I try to create a new ToDo object that's associated with an authenticated user.
I get the following error
(node:54162) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:54162) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Here is the offending code:
app.post('/todos', authenticate, (req, res) => {
var todo = new Todo({
text: req.body.text,
_creator: req.user._id
});
todo.save().then(() => {
res.send(todo);
}).catch((e) => {
res.status(400).send(e);
});
})
I am not sure what I am missing. I've read in certain places about try catch mismatches. But I am still not sure.
Just for more context, I have also added my authenticate.js
var {User} = require('./../models/user');
//Definining endpoint authentication middleware
var authenticate = (req, res, next) => {
var token = req.header('x-auth');
User.findByToken(token).then((user) => {
if(!user) {
return Promise.reject();
}
req.user = user;
req.token = token;
next();
res.send(user);
}).catch((e) => {
res.status(401).send();
});
};
module.exports = {authenticate};