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;
Related
Below is the code that I'm using to implement pagination for data retrieved from the firebase realtime database. Basically, I'm trying to get the first n content according to page number, and then getting the last n content from the data retrieved in the first query.
function getUserSnapshotOrVerifyUserId(username, idToken, cb) {
if (username == null || username.length == 0 || idToken == null || idToken.length == 0)
return cb({
status: "error",
errorMessage: "Missing params."
}, null);
admin.auth().verifyIdToken(idToken).then(decodedToken => {
let uid = decodedToken.uid;
admin.database().ref().child("users").orderByChild("username").equalTo(username).once('value', snapshot => {
if (!snapshot.exists())
return cb({
status: "error",
message: "invalid-profile"
});
snapshot.forEach(child => {
const id = child.val().id;
if (id !== uid)
return cb({
status: "error",
message: "Invalid ID"
});
admin.database().ref("users/" + id).once("value", snapshot => {
if (!snapshot.exists())
return cb({
status: "error",
errorMessage: "user not found."
});
return cb(null, id, snapshot);
});
});
});
}).catch(err => cb({
status: "error",
message: err
}));
}
exports.getUserContentTestPagination = functions.https.onRequest((req, res) => {
corsHandler(req, res, async () => {
try {
const username = req.body.username || req.query.username;
const idToken = req.body.idToken;
const limit = 2;
const page = req.body.page || 1;
const limitToFirst = page * limit;
const limitToLast = limit;
getUserSnapshotOrVerifyUserId(username, idToken, async (err, id) => {
if(err) return res.json(err);
const uploadsRef = admin.database().ref('uploads').orderByChild('createdBy').equalTo(id)
const firstnquery = uploadsRef.limitToFirst(limitToFirst);
const lastnquery = firstnquery.limitToLast(limitToLast);
lastnquery.once("value", snapshot => {
res.json({
snapshot
})
})
})
} catch (err) {
res.json({
status: "error",
message: err
})
}
});
});
This is returning a function timeout, however, when I try to get the first n data using firstnquery, it is returning the first n data as expected. So the problem is with lastnquery. Any help would be appreciated.
UPDATE 1:
exports.getUserContentTestPagination = functions.https.onRequest((req, res) => {
corsHandler(req, res, async () => {
try {
const username = req.body.username || req.query.username;
const idToken = req.body.idToken;
const limit = 2;
const page = req.body.page || 1;
let lastKnownKeyValue = null;
getUserSnapshotOrVerifyUserId(username, idToken, async (err, id) => {
if(err) return res.json(err);
const uploadsRef = admin.database().ref('uploads');
const pageQuery = uploadsRef.orderByChild('createdBy').equalTo(id).limitToFirst(limit);
pageQuery.once('value', snapshot => {
snapshot.forEach(childSnapshot => {
lastKnownKeyValue = childSnapshot.key;
});
if(page === 1){
res.json({
childSnapshot
})
} else {
const nextQuery = uploadsRef.orderByChild('createdBy').equalTo(id).startAt(lastKnownKeyValue).limitToFirst(limit);
nextQuery.once("value", nextSnapshot => {
nextSnapshot.forEach(nextChildSnapshot => {
res.json({
nextChildSnapshot
})
})
})
}
});
})
} catch (err) {
res.json({
status: "error",
message: err
})
}
});
});
It is incredibly uncommon to use both limitToFirst and limitToLast in a query. In fact, I'm surprised that this doesn't raise an error:
const firstnquery = uploadsRef.limitToFirst(limitToFirst);
const lastnquery = firstnquery.limitToLast(limitToLast);
Firebase queries are based on cursors. This means that to get the data for the next page, you must know the last item on the previous page. This is different from most databases, which work based on offsets. Firebase doesn't support offset based queries, so you'll need to know the value of createdBy and the key of the last item of the previous page.
With that, you can get the next page of items with:
admin.database().ref('uploads')
.orderByChild('createdBy')
.startAt(idOfLastItemOfPreviousPage, keyOfLastItemOfPreviousPage)
.limitToFist(pageSize + 1)
I highly recommend checking out some other questions on implementing pagination on the realtime database, as there are some good examples and explanations in there too.
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;
//Update the user's email endpoint.
apiRouter.post('/update-email', [
check('newEmail')
.isEmail().withMessage('Please Insert a valid Email')
.custom(newEmail=> {
db.query(`SELECT user_id FROM users WHERE email = ?`, newEmail,(err, res)=> {
if(res.length > 0) throw new Error('Email is already registered.');
});
})
], (req, res)=> {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json(errors);
} else {
const newEmail = req.body.newEmail;
const id = req.body.id;
userCRUDfuncs.updateEmail(id, newEmail, db, (err=> {
if(!err) {
return res.status(201).send();
} else {
return res.status(404).send();
}
}));
}
})
This code returns the following error: "throw err; // Rethrow non-MySQL errors".
I have tried using callbacks and Promises but I can never throw the error outside the query function. I could not find a way to signal the outside function to throw the error.
I really appreciate your help on this .
Thanks in advance.
Make your own custom validator and wrap your query inside a promise
.custom((value, {req}) => {
return new Promise((resolve, reject) => {
db.query(`SELECT user_id FROM users WHERE email = ?`, req.body.email,(err,res)=>
{
if(err) {
reject(new Error('Server Error')
}
if(res.length > 0) {
reject(new Error('E-mail already in use'))
}
resolve(true)
});
});
})
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I'm working in a simple API Key authentication, I just want to verify the given key against the user provied key.
I have a seperate file with the function querying the database, and returning true/false and the user object.
But in my route.js file, the return object is undefined even tough in my auth.js file it isn't.
I tried making the the function in router.get an async function using express-promise-router and making the function an await return var user = await auth.verify(req.params.uid, req.get("token")) but I don't realy know how async works.
router.js
[...]
router.get('/list/:uid', function(req, res) {
var user = auth.verify(req.params.uid, req.get("token"))
console.log("User: " + user) // <-- Undefined
if (user.status) {
res.send("Success")
} else {
res.status(403)
res.json({status: 403, error: "Unkown User / Token"})
}
})
[...]
auth.js
var db = require('./db')
var ObjectId = require('mongodb').ObjectId;
module.exports = {
verify: (uid, key) => {
try {
var collection = db.get().collection('users')
const obj_id = new ObjectId(uid)
const query = { _id: obj_id }
collection.find(query).limit(1).toArray(function(err, user) {
var status = 0;
var usr = {};
if (err) {throw err}else{status=1}
if (user.length <= 0) {throw "NotExistingExc"; status = 0}else{
usr = user[0];
if (key != usr.api) status = 0
}
var returnObj = {
status: status,
user: usr
} /* --> Is {
status: 1,
user: {
_id: d47a2b30b3d2770606942bf0,
name: 'Sh4dow',
groups: [ 0 ],
api: 'YWFiMDI1MGE4NjAyZTg0MWE3N2U0M2I1NzEzZGE1YjE='
}
}
*/
return returnObj;
})
} catch (e) {
console.error(e)
return {
status: 0,
user: {},
error: e
}
}
}
}
db.js (Idk if needed)
var MongoClient = require('mongodb').MongoClient
var state = {
db: null,
}
exports.connect = function(url, done) {
if (state.db) return done()
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
if (err) return done(err)
state.db = db
done()
})
}
exports.get = function() {
return state.db.db("database")
}
exports.close = function(done) {
if (state.db) {
state.db.close(function(err, result) {
state.db = null
state.mode = null
done(err)
})
}
}
I want to have the returnObjin auth.js in the router.get of my route.js file.
Make auth.verify return a Promise which we can then await for it inside router, You can just make the callback async no need for express-promise-router
router.get('/list/:uid', async function(req, res) {
try {
var user = await auth.verify(req.params.uid, req.get("token"))
console.log("User: " + user)
if (user.status) {
res.send("Success")
} else {
res.status(403).json({status: 403, error: "Unkown User / Token"})
}
} catch (e) {
console.error(e)
res.status(/* */).json(/* */)
}
})
auth
module.exports = {
verify: (uid, key) => new Promise((resolve, reject) => {
var collection = db.get().collection('users')
const obj_id = new ObjectId(uid)
const query = { _id: obj_id }
collection.find(query).limit(1).toArray(function(err, user) {
var status = 0;
var usr = {};
if (err) {
reject(err)
return
} else {
status = 1
}
if (user.length <= 0) {
reject(new Error("NotExistingExc"))
return
} else {
usr = user[0]
if (key != usr.api) status = 0
}
var returnObj = {
status: status,
user: usr
}
resolve(returnObj);
})
}
}
In short, the reason you get undefined is because the code in auth.js is asyncronous. But you're really close. The toArray method in MongoDB returns a promise, so you need to make sure you return that promise and then use it in the router correctly.
In auth.js, make sure verify returns a promise - just add return!
return collection.find(query).limit(1).toArray(...)
And then, change your usage of the verify to the async/await you originally tried:
router.get('/list/:uid', async function(req, res) {
var user = await auth.verify(req.params.uid, req.get("token"))
// More code here...
})
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,
});
});
};