ASYNC issue on node.js - javascript

I'm new to node and I tried to make a basic app with authentification . Data are stored on a mongoDB remote server.
My HTML form POST data to my server URL.
Here the route :
app.post('/auth', function(req, res){
handleRequest(req, res);
});
And the called handler :
function handleRequest(request, response) {
if (request.method == 'POST') {
console.log("Trying to get POST");
var body = '';
request.on('data', function (data) {
body += data;
});
// Get datas, parse them and create user with it
request.on('end', function () {
var data = JSON.parse(body);
var login = data.login;
var password = data.password;
var email = data.email;
myUser = userClass.create(login,email,password);
console.log ("email : "+email);
console.log ("password : "+password);
// authenticate with user
var auth = userClass.authenticate(myUser,function(result){
console.log("result = "+result);
});
});
}
}
The userClass.authenticate :
exports.authenticate = function(user,callback){
var result = "false";
var query = User.where(
{
email : user.email,
password : user.password
});
query.findOne(function(err,user){
if(err){return handleError(err);}
if(user){
result = "true";
}
console.log(user);
});
console.log("callback inc")
callback(result);
}
I'm pretty sure it's not optimized but it's not what I'm looking for.
When I launch the server and I send it some POST (correct) data, this strange thing happens :
My user stored in remote DB is found , so in userClass.authenticate result = true
But when the callback function is ran, the log say it's false. Did I do a something wrong in the callback ?

if query.findOne is Asynchronous, you're calling the callback before findOne is complete. Put the callback(result) inside the findOne callback - like this
exports.authenticate = function(user,callback){
var result = "false";
var query = User.where(
{
email : user.email,
password : user.password
});
query.findOne(function(err,user){
if(err){return handleError(err);}
if(user){
result = "true";
}
console.log(user);
callback(result);
});
}

Related

How to wait for API response in separate function before continuing execution?

I'm new to JavaScript/NodeJS and am having a hard time understanding what is going on here. I'm writing a function that will perform some action based on the response of an API post request within a separate function. For now, that action is just displaying a message on failure or success.
The below code (inside an app.js file) is simply meant to grab the user inputs, pass them to the login_user function (inside an authenticate.js file), and display a message based on the response from login_user.
const { login_user } = require('./authenticate');
// Other requirements
// App initialization
app.post('/auth', function (req, res) {
let username = req.body.username;
let password = req.body.password;
let response = login_user(username, password);
if (response == 204) {
res.send("Success");
} else {
res.send("Failure");
}
});
The below code (inside authenticate.js) accepts the user input, makes an API call, and returns the status code for the response.
const axios = require('axios');
const querystring = require('querystring');
function login_user(username, password) {
var data = {
j_username: username,
j_password: password
};
axios.post("https://fakeurl.com", querystring.stringify(data))
.then(function (response) {
return response.status;
})
.catch(function (error) {
return response.status;
});
}
module.exports = {
login_user
}
What happens is, once the login_user function is called, the code continues executing and goes straight to the else clause of the if/else statement, always resulting in a failure. I would like to wait for the response to be returned before executing the if/else statement.
I tried using async/await with this configuration...
app.post('/auth', async function (req, res) {
let username = req.body.username;
let password = req.body.password;
let response = await login_user(username, password);
if (response == 204) {
res.send("Success");
} else {
res.send("Failure");
}
});
...but did not have any luck. Did I do this incorrectly?
Try this,
const services = require('./authenticate');
app.post('/auth', async function (req, res) {
try {
let username = req.body.username;
let password = req.body.password;
let response = await services.login_user(username, password);
if (response == 204) {
res.send("Success");
} else {
res.send("Failure");
}
} catch (e) {
return res.status(500).json({ status: 500, message: e.message });
}
});
And,
Inside authenticate.js file
const axios = require('axios');
const querystring = require('querystring');
exports.login_user = async function (username, password) {
try {
let data = {
j_username: username,
j_password: password
};
return axios.post("https://fakeurl.com"`enter code here`, querystring.stringify(data))
.then(function (response) {
return response.status;
})
.catch(function (error) {
return response.status;
});
} catch (e) {
console.log(e);
throw Error(`Failed to evaluate transaction: ${e}`)
}
}
Use Async and await function calls in both the files.
Try this
function login_user(username, password) {
var data = {
j_username: username,
j_password: password
};
return axios.post("https://fakeurl.com", querystring.stringify(data))
.then(function (response) {
return response.status;
})
.catch(function (error) {
return response.status;
});
}
app.post('/auth', async function (req, res) {
let username = req.body.username;
let password = req.body.password;
let response = await login_user(username, password);
if (response == 204) {
res.send("Success");
} else {
res.send("Failure");
}
});
Axios return a promise
For more info you can look at this answer here : Returning data from Axios API

Getting single message from Graph

I'm trying to get a single email from an Office 365 Mailbox.
I'm sending the email id to my app via a POST (req.body.id) and then calling this code in order to get some email properties:
router.post('/id', async function(req, res, next) {
console.log("email with ID -> ", req.body.id)
let parms = { title: 'Inbox', active: { inbox: true } };
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const userName = req.cookies.graph_user_name;
if (accessToken && userName) {
parms.user = userName;
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
try {
const result = await client
.api('/me/messages/', req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();
parms.messages = result.value;
console.log("email -> ", result.value);
res.render('message', parms);
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
} else {
// Redirect to home
res.redirect('/');
}
});
At the moment, result.value contains all of the messages in the mailbox instead of just the message with provided id.
Could someone tell me where my error is, please?
The api method has a single path parameter. Calling it like .api('/me/messages/', req.body.id) is effectivly sending it a path ("/me/messages/") along with an additional parameter it ignores.
You need to send it a single string so you'll need to append the req.body.id to the path ({path} + {id}):
const result = await client
.api('/me/messages/' + req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();

Returning response from an imported function in Node.Js and Express.Js

I have an express.js post method in which I am calling a function whose code is below:
module.exports.sendEmail = function(to,subject,message){
var transporter = nodemailer.createTransport({
service : 'gmail',
auth:{
user : "",
pass : ""
}
});
var mailOptions = {
from:'findadriver9#gmail.com',
to: to,
subject:subject,
html:message
};
return transporter.sendMail(mailOptions).then(function(data){
var result ={
success:true,
message:"Email Sent"
}
return result;
}).catch(function(err){
var err={
success:false
};
return err;
});
}
How do I call the function such that depending on the success and failure I can define the response?
var response = sendEmail.sendEmail(req.body.empemail,subject,details);
res.send(response);
I tried that above way, but I am not getting any response due to asynchronous nature of Node.js.
Make changes into your sendEmail function,add one extra argument as callback function as bellow
module.exports.sendEmail = function(to,subject,message,cb){
var transporter = nodemailer.createTransport({
service : 'gmail',
auth:{
user : 'demo.user#mail.com',
pass : 'demo#password'
}
});
var mailOptions = {
from:'demo.user#mail.com',
to: to,
subject:subject,
html:message
};
return transporter.sendMail(mailOptions).then(function(data){
var result ={
success:true,
message:"Email Sent"
}
cb(result);
}).catch(function(err){
var err={
success:false
};
cb(err);
});
}
Here, this function will not return any result but after complition of work it will send result to callback function.
Now call this function as bellow
sendEmail.sendEmail(req.body.empemail,subject,details,function(result){
res.send(result);
});
You need to await the email being sent:
app.post("/mail", async function(req,res){
const response = await sendEmail.sendEmail(req.body.empemail,subject,details);
//do whatever
res.send(response);
});
Doing the same with good (old) promises only:
app.post("/", function(req, res){
sendEmail
.sendEmail(req.body.empemail,subject,details)
.then(function(response){
//do whatever
res.send(response);
});
});

request.session.regenerate not working, undefined 'undefined'

I've got this issue:
request.session.regenerate(function() {
request.session.user = username;
return response.send(username);
});
When logging in I always get undefined error:
Cannot read property 'regenerate' of undefined
If I just leave return response.send(username); it works fine, however I need to create a session.
What could be the issue?
More code
router.post('/login', bodyParser, function(request, response) {
var username = request.body.username;
var password = request.body.password;
adminUser.findOne({
username: username
}, function(err, data) {
if (err | data === null) {
return response.send(401, "User Doesn't exist");
} else {
var usr = data;
if (username == usr.username && bcrypt.compareSync(password, usr.password)) {
request.session.regenerate(function() {
request.session.user = username;
return response.send(username);
});
} else {
return response.send(401, "Bad Username or Password");
}
}
});
});
Added: app.use (session());
Now its working.
Making my comment into an answer since it appears to have solved your issue...
Express does not automatically have request.session. You have to be using some middleware that creates that like express-session. If you are using express-session, then you would add:
const session = require('express-session');
and
app.use(session({secret: 'my super secret'}));

Node js custom callback function error

I'm trying to make a simple authentication with node js. Because I read user data from a database, I have to make it asynchronous. Here's my function, which checks if authentication is ok:
function auth(req, callback) {
var header = req.headers['authorization'];
console.log(cb.type);
console.log("Authorization Header is: ", header);
if(!header) {
callback(false);
}
else if(header) {
var tmp = header.split(' ');
var buf = new Buffer(tmp[1], 'base64');
var plain_auth = buf.toString();
console.log("Decoded Authorization ", plain_auth);
var creds = plain_auth.split(':');
var name = creds[0];
var password = creds[1];
User.findOne({name:name, password:password}, function(err, user) {
if (user){
callback(true);
}else {
callback(false);
}
});
}
}
And here I call the function:
auth (req, function (success){
if (!success){
res.setHeader('WWW-Authenticate', 'Basic realm="myRealm');
res.status(401).send("Unauthorized");
}else{
if(user!==req.user) {
res.status(403).send("Unauthorized");
}else{
User.findOneAndUpdate({user:userid}, {user:req.body.user, name:req.body.name, email:req.user.email, password:User.generateHash(req.body.password)},
{upsert:true}, function(err, user) {
if(!err) {
res.status(200).send("OK");
}else{
res.status(400).send("Error");
}
});
}
}
});
This gives me error "TypeError: object is not a function", pointing at "callback(false)". I have no idea what could cause this error, as I pass a function as a parameter, and the first log message prints "[function]". Any help would be appreciated.

Categories

Resources