This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 4 years ago.
I have some code like this:
let addUser = (req, res) => {
let user;
let message = "";
let status = 200;
bcrypt.hash(password, salt_rounds, (err, hash) => {
user = new user({
...
password: hash,
});
user.save(err => {
if(err) {
message = "No success";
status = 400;
} else {
message = "success";
}
});
res.status(status).json({
message: message,
});
});
};
However, the message variable is undefined when the response is sent. I've been searching for a while now and, unfortunately, haven't been able to find a solution similar to this problem.
Ultimately, what I would like is to be able to update the message, status, etc. variables within the bcrypt/.save closures. I have tried using callbacks and resolving promises which I'm assuming didn't work due to naivety. Regardless, any solution would be appreciated!
Note: I would not like to use any other libraries to solve this problem (which I really doubt is required in the first place)
Thanks in advance!
Change user.save into something that returns a Promise, and then call .then on that Promise:
let addUser = (req, res) => {
let user;
let status = 200;
bcrypt.hash(password, salt_rounds, (err, hash) => {
user = new user({
password: hash,
});
const savePromise = new Promise((resolve, reject) => {
user.save(err => {
if (err) {
status = 400;
reject("No success");
} else {
resolve("success");
}
});
});
savePromise.then(message =>
res.status(status).json({ message })
).catch(message =>
res.status(status).json({ message })
);
});
};
Try this, put message key in double quotes
let addUser = (req, res) => {
let user;
let message = "";
let status = 200;
bcrypt.hash(password, salt_rounds, (err, hash) => {
user = new user({
...
password: hash,
});
user.save(err => {
if(err) {
message = "No success";
status = 400;
} else {
message = "success";
}
});
res.status(status).json({
"message": message,
});
});
};
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
How to properly return a result from mysql with Node?
(6 answers)
Closed 25 days ago.
This post was edited and submitted for review 25 days ago.
I' m building a email verification for my website in node.js and for it to work it changes a value in a mysql database, it has to return 1 or 0 if it works or doesn't work but the code doesn' t wait for the return and inmidiatly goes further even though I use async and await.
this is the code I used in the pages.js:
router.get("/verify-email", async (req,res) => {
var tokens = req.query.token
console.log(tokens)
const verified = await emailverification(tokens)
console.log("hello",verified)
if (verified == 1) {
res.sendFile('verifySuccess.html',{root: "./public"});
} else {
res.sendFile('verifyFail.html',{root: "./public"});
}
})
and this is the funciton it has to wait for:
const emailverification = async(token,req,res,next) => {
var tokens = token
console.log("hello",tokens)
db.query('SELECT * FROM users WHERE token = ?',[tokens], async(err, result) =>{
console.log("1")
if (err) throw err;
console.log(result)
if(result[0].verify == "0"){
console.log("2")
console.log(result[0].email)
if (result.length > 0) {
console.log("2.5")
var email = result[0].email
console.log(email)
console.log("2.75")
db.query('UPDATE users SET verify = 1 WHERE email = ?', email, async(err, result) => {
console.log(result[0])
console.log("3")
if(err) throw err
return 1
})
} else {
console.log("5")
return 0;
}
}else{
console.log("6")
return 0;
}
})
}
module.exports = emailverification;
I searched on goolge and here on stackoverflow and found a lot of stuff about this but it doesn't work in my code.
this is the source code: the source code
the follwing 2 questions:
how-do-i-return-the-response-from-an-asynchronous-call and how-to-properly-return-a-result-from-mysql-with-node don't help because those questions ar abour something else and not about the problem I have. because by my problem the code doesn' t return the stuff before contini=uing even though I use the async/awaint things like they do by these 2 questions
please don't mind all the logs I use them to see what runs and what doesn't,
you have to return like this.
const emailverification = async (req, res) => {
var tokens = req.tokens;
return db.query(
"SELECT * FROM users WHERE token = ?",
[tokens],
async (err, result) => {
if (err) throw err;
if (result[0].verify == 0) {
console.log(result[0].email);
if (result.length > 0) {
var email = result[0].email;
console.log(email);
console.log("2.75");
db.query(
"UPDATE users SET verify = 1 WHERE email = ?",
email,
async (err, result) => {
console.log(result[0]);
console.log("3");
if (err) throw err;
}
);
return res.status(200).send({ message: "true" });
} else {
var message = { status: "error", error: "email already verified" };
console.log("5");
return res.status(400).send({ message: "false" });
}
} else {
console.log(result);
console.log("6");
message = { status: "error", error: "email already verified" };
return res.status(400).send({ message: "false" });
}
}
);
};
module.exports = emailverification;
I have been working on my first node.js backend and I am trying to refactor the login function, but i am not understanding something about promise chaining and error handling. I am hoping someone can help point out what I am missing here.
I have read about promise chaining and I understand that one catch should be able to handle any error in the chain, but I cant seem to get it to work without having an individual .catch for every .then
Here is my userLogin function.
const loginUser = handleAsync(async (req, res, next) => {
let userEmail = req.body.email;
let submittedPassword = req.body.password;
userLogin(userEmail, submittedPassword)
.then((userObject) => {
res.json(userObject);
})
.catch((err) => {
res.status(401).send(err);
console.log("any error inside userLogin: " + err);
});
});
async function userLogin(email, submittedPassword) {
console.log("in user login");
return new Promise(function (resolve, reject) {
getUserAccountByEmail(email)
.then((userAccountResults) => {
let email = userAccountResults[0].email;
let storedPassword = userAccountResults[0].password;
//the user exists check the password
//the user exists. Now Check password.
checkUserPassword(submittedPassword, storedPassword)
.then((passwordIsAMatch) => {
//The password is a match. Now Generate JWT Token.
generateJWTToken(email)
.then((tokens) => {
//build json object with user information and tokens.
createUserDataObject(tokens, userAccountResults)
.then((userObject) => {
//send the user object to the front end.
resolve(userObject);
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
})
.catch((err) => {
reject(err);
});
});
}
And here is one of the functions that is a part of the chain
function getUserAccountByEmail(email) {
return new Promise(function (resolve, reject) {
logger.info("Looking up user email");
const users = User.findAll({
where: {
email: email,
},
limit: 1,
attributes: [
"email",
"password",
"userId",
"stripeConnectAccountId",
"isStripeAccountSet",
"stripeCustomerId",
],
})
.then((userResults) => {
if (doesUserExist(userResults)) {
resolve(userResults);
} else {
console.log("user doesnt exist in getuseraccount");
reject("User Email Does Not Exist In Database");
}
})
.catch((error) => {
console.log("Error Accessing Database: UserAccountByEmail");
logger.error("Error in getUserAccountByEmail: " + error);
});
});
}
Any help would be appreciated. Thanks
I took jfriend00 's advice and refactored using await instead of nesting.
async function userLogin(email, submittedPassword) {
return new Promise(async function (resolve, reject) {
try {
//Get User Account Information
const userAccountResults = await getUserAccountByEmail(email);
//Password Authentication
let storedPassword = userAccountResults[0].password;
const passwordIsAMatch = await checkUserPassword(
submittedPassword,
storedPassword
);
//Generate JWT Tokens
const tokens = await generateJWTToken(email);
//Prepare user data JSON for sending to the frontend.
const userData = await createUserDataObject(tokens, userAccountResults);
resolve(userData);
} catch (error) {
reject(error);
}
});
}
I'm trying to implement a HTTP server in node.js. I want to do the following:
receive a registration request from a client application;
try to add the user to the server's database;
notify the client application whether the registration succeeded or not (due to a possible duplicate username, for example).
Here's the code that I currently have:
request.on('end', () => {
if (!this.checkLevel())
return;
const username = this.json_data.username;
const full_name = this.json_data.full_name;
const new_user_lvl = this.json_data.new_user_lvl;
const oid = this.generateOID(12);
database.addUser(username, full_name, new_user_lvl); //code below
database.addValidOID(oid, username);
const body = oid;
response.writeHead(200, {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'text/plain'
});
response.end(body);
});
//database.addUser
function addUser(username, full_name, clearance_lvl)
{
const db = new sqlite3.Database(DB_PATH + DB_NAME);
const stmt = db.prepare("INSERT INTO User(username, full_name, clearance_lvl) VALUES (?,?,?)");
stmt.run(username, full_name, clearance_lvl, function (err){
if (err) throw err;
console.log(`[Database] Added New User (${username})`);
});
stmt.finalize();
db.close();
}
Given the current code, I don't know how to possibly catch the exceptions generated by addUser to create my http responses accordingly. I've already tried surrounding addUser with a try/catch block and it had no effect. Can someone help me with this?
Try adding addUser line to try catch block ?
Meanwhile I found this question and changed my approach to use promises.
Here's the working code:
function SQLRunPromise(connect, stmt, params)
{
return new Promise(function(resolve, reject) {
connect.run(stmt, params, function cb(err) {
if(err) {
let responseObj = {
'error': err
}
reject(responseObj);
} else {
let responseObj = {
'statement': this
}
resolve(responseObj);
}
});
});
}
//database.addUser
async function addUser(username, full_name, clearance_lvl)
{
const db = new sqlite3.Database(DB_PATH + DB_NAME);
const stmt = "INSERT INTO User(username, full_name, clearance_lvl) VALUES (?,?,?)";
const params = [username, full_name, clearance_lvl];
const promise = SQLRunPromise(db, stmt, params);
db.close();
return promise;
}
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;
I am able to successfully add a row to a google spreadsheet using the google-spreadsheet node module as follows:
const logToGoogleSpreadsheet = (userName, description, link) => {
const spreadsheetId = 'my-spreadsheet-id'
const doc = new GoogleSpreadsheet(`${spreadsheetId}`)
const clientEmail = 'my-client-email'
const privateKey = 'my-private-key'
const payload = {
client_email: clientEmail,
private_key: privateKey
}
let status = ''
doc.useServiceAccountAuth(payload, function (err) {
doc.addRow(1, { 'Reported By': userName, 'Description': description, 'Screenshot Link': link, 'Status': 'Open' }, function(err) {
if(err) {
console.log(err);
status = 'some error'
} else {
console.log('It worked')
status = 'success'
}
});
})
return status
}
const result = logToGoogleSpreadsheet('username', 'description', 'link')
console.log(`The value of result is ${result}`) //This always shows undefined as the value
The value of result always is 'undefined'. I know this is due to the asynchronous nature of javascript and being unable to modify anything in a callback function, but im not able to fix this issue. Can someone please show me an example of how i can return the status from the logToGoogleSpreadsheet function ?
Thank You
you could do this:
const logToGoogleSpreadsheet = *async* (userName, description, link) => {//add async keyword
const spreadsheetId = 'my-spreadsheet-id'
const doc = new GoogleSpreadsheet(`${spreadsheetId}`)
const clientEmail = 'my-client-email'
const privateKey = 'my-private-key'
const payload = {
client_email: clientEmail,
private_key: privateKey
}
let status = ''
doc.useServiceAccountAuth(payload, function (err) {
doc.addRow(1, { 'Reported By': userName, 'Description': description, 'Screenshot Link': link, 'Status': 'Open' }, function(err) {
if(err) {
console.log(err);
status = 'some error'
} else {
console.log('It worked')
status = 'success'
}
});
})
return status
}
logToGoogleSpreadsheet('username', 'description', 'link').then(res => console.log(res));
adding the async keyword to logToGoogleSpreadsheet will make it return a Promise. Now it is a 'thenable' meaning the then method can be called with the resolved result, which here is your status. So in the then call we log it.