How to add async/await in function login nodejs? - javascript

I just learned Nodejs, now I'm having a problem that I don't know how to add async/await in function service login. I researched today without finding a solution. Please help me. Thank you very much!
userService.js
exports.findUser = async (email, password) => {
var result = null;
User.findOne({
email: email,
password: password,
})
.then((data) => {
if (data) {
result = data;
}
})
.catch((err) => {});
return result;
};
userController.js
exports.login = (req, res, next) => {
var email = req.body.email;
var password = req.body.password;
var data = userService.findUser(email, password);
console.log(data);
if (data !== null) {
res.status(200).json({ message: "null" });
} else {
res.status(401).json({ message: "Incorrect email or password!" });
}
};

Solution
From userService.js it is clear you are using mongoose. to use async and await in nodejs you can edit your code like this...
exports.findUser = async (email, password) => {
try{
var result = await User.findOne({
email: email,
password: password,
})
return result
}catch(e){
// catch errors and do something
}
}
Notice i used try and catch block so that i can catch error if anything goes wrong in the await. after the await resolves you get back a mongodb document same as you will get in the parameter passed to .then in a promise callback function.

The thing with async functions is it allows you to await a promise, basicallly suspending the execution of the function until the promise resolves. So, your code could be rewritten as:
//userService.js
exports.findUser = async (email, password) => {
var result = null;
try{
result = await User.findOne({
email: email,
password: password,
})
} catch(e){
\\handle error
}
return result;
};
//userController.js
exports.login = async (req, res, next) => {
var email = req.body.email;
var password = req.body.password;
var data = await userService.findUser(email, password);
console.log(data);
if (data !== null) {
res.status(200).json({ message: "null" });
} else {
res.status(401).json({ message: "Email hoặc mật khẩu không đúng!" });
}
};
By making both functions async, you can take advantage of the await keyword and promises without the 'callback hell' that appears with .then() and .catch() on promises.
MDN Docs

Related

How to fix Data and hash arguments required error

I'm trying to let the user sign in using either email or username, I'm trying this code in Postman and each time I try it gives me this error:
"success":false,"status":500,"message":"data and hash arguments
required","stack":"Error: data and hash arguments required\n at
Object.compare
Auth.js Configurations:
const emailRegex = "/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/";
router.post("/login", async (req, res, next) => {
const isEmail = String(req.body.emailOrUsername).match(emailRegex);
try {
if (!req.body.password) {
return next(createError(400, "Invalid password"));
}
let user;
if (isEmail) {
user = await User.findOne({ where: { email: req.body.emailOrUsername } });
} else {
user = await User.findOne({ where: { username: req.body.emailOrUsername } });
};
if (!user) return next(createError(404, "User not found!"));
const isPasswordCorrect = await bcrypt.compare(
req.body.password,
user.password
);
if (!isPasswordCorrect) return next(createError(400, "Wrong password!"));
const { password, ...others } = user._doc;
res.status(200).json(others);
} catch (err) {
next(err);
}
});
I'm not sure what I'm missing here!

What is the problem in the nodejs controller function?

exports.signupController = async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOne({ phone }).exec()
if (user) {
return res.status(400).json({
errorMessage: 'Phone Number already exists',
});
}
const newUser = new User();
newUser.phone = phone;
const salt = await bcrypt.genSalt(10);
newUser.password = await bcrypt.hash(password, salt);
await newUser.save();
return res.status(200).json({
successMessage: 'Registration success. Please login',
});
} catch (err) {
console.log('signupController error: ', err);
res.status(500).json({
errorMessage: 'Server error',
});
}};
**I upload a node application in shared hosting! **
*But an error was showing in this controller function. All the time the catch block is running on the json. The error is unhandled promise rejection. *
signup(data)
.then((response) => {
console.log('Axios signup success: ', response);
setFormData({
phone: '',
password: '',
password2: '',
loading: false,
successMsg: response.data.successMessage,
});
history.push('/signin');
})
.catch((err) => {
console.log('Axios signup error: ', err);
setFormData({
...formData,
loading: false,
errorMsg: err.response.data.errorMessage,
});
});
this is react front end event handler
import axios from 'axios';
export const signup = async (data) => {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const response = await axios.post('/api/auth/signup', data, config);
return response;
};
the signup api function
Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. If you need a fully-fledged promise, use the .exec() function. for example:
const query = Band.findOne({name: "Guns N' Roses"});
assert.ok(!(query instanceof Promise));
// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function (doc) {
// use doc
});
// `.exec()` gives you a fully-fledged promise
const promise = query.exec();
assert.ok(promise instanceof Promise);
promise.then(function (doc) {
// use doc
});
If you are using exec() on your findOne query you should use:
exports.signupController = async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOne({ phone }).exec();
/// just a pseudo code
user.then('do your things').catch( 'log error')
const newUser = new User();
newUser.phone = phone;
const salt = await bcrypt.genSalt(10);
newUser.password = await bcrypt.hash(password, salt);
await newUser.save();
return res.status(200).json({
successMessage: 'Registration success. Please login',
});
} catch (err) {
console.log('signupController error: ', err);
res.status(500).json({
errorMessage: 'Server error',
});
}};
for more details check this out: https://mongoosejs.com/docs/promises.html#should-you-use-exec-with-await?

catch error of my exported async/await function [duplicate]

This question already has answers here:
Why is it possible to try-catch an async-await call?
(2 answers)
Closed 2 years ago.
I have module that check username is unique or no!
my module is:
// Check for uniqueness username
const UsernameUniqueness = async (_username) => {
const username = await Users.findOne({
username: _username
});
if (username) {
return false;
}
return true;
}
exports.UsernameUniqueness = UsernameUniqueness;
and I have a route that I post username to it.
const FormUniqueness = require('../modules/form-uniqueness');
router.post('/register', redirectDashboard, async (req, res, next) => {
const ( username } = req.body;
try {
console.log(FormUniqueness.UsernameUniqueness(userName));
} catch (error) {
// Internal server error 500
console.log('here');
error.status = 500;
next(error);
}
}
I want when I have an error in "const username = await Users.findOne({
username: _username
}); my error throw in try/catch of my route!"
How can I do this?
Catch the error also in your function
const UsernameUniqueness = async (_username) => {
try {
const username = await Users.findOne({
username: _username
});
if (username) {
return false;
}
return true;
} catch(error) {
throw error;
}
}
exports.UsernameUniqueness = UsernameUniqueness;

Bcrypt.compareSync always returning false

Hi so I'm trying to create my first login with sequelize and I'm struggling with hashing and comparing hashes and it always returns false.
I figured I am doing something wrong on the hashes or comparing since I'm learning. I'm using SQL database
Here's my login code, I'm using express session and sequelize:
'processLogin': (req, res) => {
db.User.findOne({
where: {
email: req.body.email
}
})
.then(async user => {
var eSession = req.session.userLogin
let checkPass = await bcrypt.compare(req.body.password, user.password)
console.log(checkPass);
if(checkPass){
eSession = user;
res.send("Success");
}else{
res.render('login', {errors: [{
msg: "Incorrect password"
}]});
}
if(user == undefined){
res.render('login', {errors: [{
msg: "User not found, please Register"
}]});}
})
}
And here is where I actually hashed the passwords on my register:
'save': async (req, res) => {
var a = [req.body.fullname, req.body.email, req.body.number, bcrypt.hashSync(req.body.password, 10), bcrypt.hashSync(req.body.repassword, 10)];
let errors = validationResult(req);
if(errors.isEmpty()){
db.User.create({
full_name: a[0],
email: a[1],
phone_number: a[2],
password: await bcrypt.hash(a[3], 10),
confirm_password: await bcrypt.hash(a[4], 10)
})
.then(users => {
res.send("succes!!");
})
}else{
res.render('register', { errors: errors.errors })
}
}
}
insted of sync why don't you try async and wait unitll it get's hashed or decrypt.
inside async function to hash password.
let hashedPassword = await hash(password, 10);
and inside async function for comparing password
let checkPass = await compare(password, foundUser.password);

How could I refactor the waterfall method from async to use ES6 promises?

I have a route that allows a user to reset their password by sending them an email. Standard procedure for most websites. In this route, I import the async npm module and use the waterfall method so that I can handle the asynchronous nature of multiple functions. I'm still having a bit of trouble understanding promises, but I'm trying to replace waterfall with a promise or promise chain.
How could I refactor this route with a promise? Here are the steps contained in this route that is currently split up into 4 functions with waterfall.
First the route creates a reset token
Search for user based on email
2.5. If user is found, save user, otherwise return 404
Send email to user containing a reset url
Return a status of 200.
app.post('/forgotPassword', function(req, res, next) {
waterfall([
// generate reset token
function(done) {
crypto.randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
// search for user with the given email
User.findOne({ email: req.body.email }, function(err, user) {
// check to see if the user exists
if (!user) {
// user doesn't exist in database
return res.status(404).send();
}
// user exists, assign token with expiration date
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour from now
// save the user model with the newly added
// token and expiration date
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'SendGrid',
auth: {
user: config.sendgridUser,
pass: config.sendgridPassword
}
});
var mailOptions = {
to: user.email,
from: 'email#school.edu',
subject: 'Password Reset',
text: `Hello etc etc`,
smtpTransport.sendMail(mailOptions, function(err) {
done(err, 'done');
});
}],
function(err) {
// handle error
if (err) return next(err);
res.status(200).send();
});
}); // end POST route '/forgotPassword'
Promise is a very powerful tool. It can be hard to understand it at the beginning, but totally worth the effort! Please let me know if you have any doubts :)
app.post('/forgotPassword', function(req, res, next)
{
new Promise((resolve, reject) =>
{
// generate reset token
crypto.randomBytes(20, (err, buf) =>
{
if(err)
return reject(err);
const token = buf.toString('hex');
resolve(token);
});
})
.then((token) =>
{
return new Promise((resolve, reject) => {
// search for user with the given email
User.findOne({ email: req.body.email }, (err, user) =>
{
if (!user)
return reject(404);
// user exists, assign token with expiration date
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour from now
// save the user model with the newly added
// token and expiration date
user.save(function(err) {
if(err)
return reject(err);
resolve(user);
});
});
});
})
.then((user) =>
{
return new Promise((resolve, reject) =>
{
const smtpTransport = nodemailer.createTransport('SMTP',
{
service: 'SendGrid',
auth: {
user: config.sendgridUser,
pass: config.sendgridPassword
}
});
const mailOptions = {
to: user.email,
from: 'email#school.edu',
subject: 'Password Reset',
text: `Hello etc etc`
};
smtpTransport.sendMail(mailOptions, (err) =>
{
if(err)
return reject(err);
resolve();
});
});
})
.then(() => res.sendStatus(200))
.catch((err) =>
{
//check if the error is the one from the DB where the user was not found
if(err == 404) {
return res.sendStatus(404);
}
return res.status(500).send(err);
});
});
bluebird is one of the most popular promise library.
and it offers promisify function to convert callback hell to promise.
please read this document and play with it.
http://bluebirdjs.com/docs/working-with-callbacks.html
This answer presumes 4 completely sequential steps:
(Function () {
Return Promise (function (resolve, promise) {
// try to do some stuff
if (success) {
Resolve ("pass this value on to next link in the chain");
}
Reject();
})()
.then (function (value) {
// do next step
Return "pass this value on to next link in the chain";
.then (function (value) {
// do next step
Return "pass this value on to next link in the chain";
.catch (function (error) {
// handle any reject or any error in the chain
}
You could in relation to the individual .then also choose to return a Promise. Beware: any errors in the .catch block will be swallowed.
This is just an example with ES6 promise but working code. You can refactor it further to have a clear reusable code. You can replace ES5 functions with ES6 arrow functions.
app.post('/forgotPassword', function(req, res, next) {
var catch = function(err){
return next(err);
}:
var error404 = function(){
return res.status(404).send();
};
var success = function(){
return res.status(200).send();
};
var step1 = new Promise(function(resolve, reject){
crypto.randomBytes(20, function(err, buf) {
if(err){
reject(err);
} else {
var token = buf.toString('hex');
resolve(token);
}
});
});
var step2 = function(token) {
// search for user with the given email
User.findOne({ email: req.body.email }, function(err, user) {
// check to see if the user exists
if (!user) {
// user doesn't exist in database
return {error404: true};
}
// user exists, assign token with expiration date
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour from now
// save the user model with the newly added
// token and expiration date
user.save(function(err) {
return { error: err, token: token, user: user });
});
});
};
var step3 = function(obj) {
if(obj.error){
return catch(obj.error);
} else if(obj.error404) {
return error404();
} else {
var token = obj.token, user = obj.user;
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'SendGrid',
auth: {
user: config.sendgridUser,
pass: config.sendgridPassword
}
});
var mailOptions = {
to: user.email,
from: 'email#school.edu',
subject: 'Password Reset',
text: `Hello etc etc`,
smtpTransport.sendMail(mailOptions, function(err) {
if(err){
return catch(err);
} else {
return success();
}
});
}
};
step1.then(step2, catch).then(step3);
}); // end POST route '/forgotPassword'
Promises work best when you're dealing with a library where methods already return them, or a library like bluebird that lets you promisify existing callback APIs, otherwise it's a lot of conversions.
If you're still set on refactoring with plain es6, put your promise-wrappers at the lowest possible level, for best effect and cleanest error handling, basically promisify manually:
let convert = (resolve, reject) => (err, res) => err ? reject(err) : resolve(res);
crypto.randomBytesAsync = n=>new Promise((y,n)=>crypto.randomBytes(n,convert(y,n)));
User.findOneAsync = u => new Promise((y, n) => User.findOne(u, convert(y, n)));
User.prototype.saveAsync = () => new Promise((y, n) => this.save(convert(y, n)));
Then use them like this:
app.post('/forgotPassword', function(req, res, next) {
crypto.randomBytesAsync(20).then(buf => {
var token = buf.toString('hex');
// search for user with the given email
return User.findOneAsync({ email: req.body.email }).then(user => {
// check to see if the user exists
if (!user) {
// user doesn't exist in database
res.status(404).send();
throw;
}
// user exists, assign token with expiration date
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour from now
// save the user model with the newly added
// token and expiration date
return user.saveAsync().then(() => {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'SendGrid',
auth: { user: config.sendgridUser, pass: config.sendgridPassword }
});
smtpTransport.sendMailAsync =
o => new Promise((y, n) => smtpTransport.sendMail(o, convert(y, n)));
return smtpTransport.sendMailAsync({
to: user.email,
from: 'email#school.edu',
subject: 'Password Reset',
text: `Hello etc etc`,
});
});
})
})
.then(() => res.status(200).send())
.catch(err => next(err));
}); // end POST route '/forgotPassword'

Categories