How to return responses in nodejs? - node.js

I have below code:
exports.generateCo = async function(req,res,next){
//some code
return new Promise(function (resolve,reject){
if(err){
//some code
}
else{
//some code
let mail = await sendEmail.otp(val,mailid,sub);
console.log("mail -- ",mail);
}
})
}
In Another file:
exports.otp = async function(val,mailid,sub){
//some code
transporter.sendMail(options,(error,info) =>
if(error){
//error logs
respobj = {status: "err"};
}
else{
//success logs
respobj = {status: "success"};
}
return respobj;
}
Here in the first file, Im not able to get the response in "mail" variable. Im getting "undefined" value. Can anybody please help me with this?

The await wont work inside a promise.
As per the given code,you do not need to define a new promise inside the async function.
If you need the new promise, you cannot you the await inside a promise callback. You should the then format instead.
sendEmail.otp(val,mailid,sub).then((mail) => {
console.log("mail -- ",mail);
})
Also, the otp function has a callbck, so it has to be wrapped in a
promise.
exports.otp = async function(val,mailid,sub) {
//some code
return new Promise((resolve, reject) = {
transporter.sendMail(options,(error,info) => {
if(error){
//error logs
respobj = {status: "err"};
} else {
//success logs
respobj = {status: "success"};
}
return resolve(respobj);
})
})
}

Is the final return in right spot? That's usually what I find I made a mistake.

Make call back function as async then use await.
Return respobj from with in call back, if you try to return the response from outside of the callback then before waiting for any transporter.sendMail it will return undefined.
exports.generateCo = async function(req,res,next){
//some code
return new Promise(async function (resolve,reject){
if(err){
//some code
}
else{
//some code
let mail = await sendEmail.otp(val,mailid,sub);
console.log("mail -- ",mail);
}})
}
exports.otp = async function(val,mailid,sub){
//some code
transporter.sendMail(options,(error,info) => {
if(error){
//error logs
respobj = {status: "err"};
}
else{
//success logs
respobj = {status: "success"};
};
return respobj});
}

Related

nodejs wait for function response (MYSQL script) before responding to API call

I have read responses for about 3 hours now regarding using promises or callbacks or async/await for my issue but I can't figure it out.
I have a list of items to upload via a MYSQL stored procedure.
It all works however if there is an error I want to return a correct response, instead of crashing, plus probably add some more data in the successful response.
For the sake of saving space below I have deleted my variable list etc. The call does work, I just want to return TRUE or FALSE from the function [uploadScripts] but instead the code is jumping past and not waiting.
router.post('/addTempScript/',verify, async (req,res) => {
const curPatient = req.body;
let scriptList = curPatient.scripts;
let success = await uploadScripts(scriptList);
console.log("Successful upload? " + success);
if (success) {
return res.status(200).json({
Result: true
})
}
else
{
return res.status(460).json({
Result: false
})
}
});
function uploadScripts(scriptList){
try{
scriptList.forEach(script =>{
let MYLISTOFVARIABLES
try{
var sqlString = "SET #MYVARIABLES; \
CALL addTempScript(#MYVARIABLES);";
connection.query(sqlString,[MYVARIABLES], async (err,rows,fields)=>{
if(err){
console.log(err.message);
return false;
}
})
} catch (e) {
// this catches any exception in this scope or await rejection
console.log(e);
return false;
}
})
return true;
} catch(error) {
return false;
}
}

Getting [object Promise] when outputting result of promise

I am getting Result is: [object Promise] when I am calling this promise. I want to be able to work with the data that comes out of it. I am expecting the result to be an array of messages from my SQS queue.
I currently have more than 10 messages in the queue so should be fine finding some.
This is my code currently:
let params = {
QueueUrl: config.aws.serviceQueue,
VisibilityTimeout: 60,
MaxNumberOfMessages: 10
};
let getMonitors = sqs.receiveMessage(params).promise();
let result = getMonitors.then(function(data) {
console.log('Success');
return data;
}).catch(function(err) {
console.log(err);
});
console.log(`Result is: ${result}`);
What am I missing here? I am very new to promises so please bear with me if I don't understand your answer or question.
Yeah, the result of getMonitors().then() is a promise object so the result variable is indeed a promise object. That's how promises work.
If you want to access the value inside the promise, you either use .then() on the promise or you use await (inside an async tagged function).
In this particular code, you should just be consuming the result inside your .then() handler. That's where you have the value.
You return something in then and try to assign it to any variable you will end up with having promise.
What you can do is
let params = {
QueueUrl: config.aws.serviceQueue,
VisibilityTimeout: 60,
MaxNumberOfMessages: 10
};`
let getMonitors = sqs.receiveMessage(params).promise();
/*let result = getMonitors.then(function(data) {
console.log('Success');
return data;
}).catch(function(err) {
console.log(err);
});*/
//console.log(``Result is: ${result}``);`
getMonitors.then(function (result) {
console.log(result);
}).catch(function (err) {
console.log(err);
});
or you can use Async and await ::
const someFunction = Async() => {
/* your all code inside*/
let result = await getMonitors();
console.log(Result is: $ {
result
});
or
console.log(Result is: $ {
await result
});
}
You might be trying to look at the data before the promise has resolved. Async/ await will probably help.
async function happyLittleFunc() {
const params = {
QueueUrl: config.aws.serviceQueue,
VisibilityTimeout: 60,
MaxNumberOfMessages: 10
};
let getMonitors;
try {
getMonitors = await sqsReceieveMessage(params);
} catch (err) {
console.log(err);
return;
}
console.log(`Result is: ${getMonitors}`);
}
// Call sqs
function sqsReceieveMessage(params) {
return new Promise(async (resolve, reject) => {
let messageData;
try {
messageData = await sqs.receiveMessage(params);
} catch (err) {
reject(err);
}
resolve(messageData);
});
}
happyLittleFunc();

logging errors in async functions

I have this code:
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0;
} catch (err) {
return err;
}
}
getURL().then( result => {
if (result === 0) console.log("success");
else console.log(result);
});
The fetch will fail and the error is logged to the console. How do I rework the code so it uses async and try/catch everywhere? That is, I'm looking to avoid doing getURL().then for the sake of consistency.
EDIT:
For those downvoting me, await getURL() won't work as it's invalid syntax.
EDIT2:
Tried this but it didn't catch the error:
async function getURL() {
return await fetch("http://www.blah.com");
}
let result = async function() {return await getURL();}
try {
result();
} catch (e) {
console.log(e);
}
You can wrap your whole code inside an instantly executed async function like this:
// service.js
async function getURL() {
return await fetch("http://www.blah.com");
}
// your.module.js
(async function() {
// do things...
try {
let result = await getURL();
} catch (e) {
console.log(e);
}
// do things...
res.send({});
});
Every time you need to catch an error from promise, either using new Promise, async-await or generator you need to use .then() or you can do something like this another async-await.
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // EDIT: just returning value which is success
} catch (err) {
return err; // EDIT: returning value not rejecting a promise
}
}
async function main () {
try {
let result = await getURL();
if (result === 0) console.log("success");
console.log(result); // EDIT: error will be print.
}
catch (err) { // EDIT: getURL() never rejects so always success.
console.log(err);
}
});
main();
This situation doesn't really occurs as while our main function in server-side or client-side are async and handling this for us.
Like using express:
app.post('/api', async (req, res) => {
try {
let result = await getURL();
res.send(async);
}
catch(err) {
res.send(err);
}
});
EDIT: asyn-await doesn't reject or resolve a call, just return a value. thus must be used carefully.
function fetch(url) {
return new Promise( (resolve, reject) => {
let x = Math.floor(Math.random() * Math.floor(9) + 1);
// 50-50 resolve or reject
if(x%2===0) return resolve(false); //resolve with `false` statement
reject(true); // reject with `true` still a reject
});
}
async function getURL() {
try {
await fetch("http://www.blah.com");
return 0; // if fetch resolve
} catch (err) { //only if fetch reject
return err;
}
}
async function main () {
try {
let result = getURL();
if (result === 0) console.log("success"); //getURL never reject any call
console.log(result);
}
catch (err) { // getURL doesnt reject
console.log(err);
}
};
main();
I realize now async functions always return a promise. Even if you throw an error it still gets wrapped up into a promise. Therefore using try/catch won't help. This is how I ended up writing the code:
async function getURL() {
return await fetch("http://fake");
}
getURL().then( () => console.log("success")).catch( (e) => console.log(e));

if/else with async code in one case

I don't have much experience in async code and I'm stuck with a problem, here is my code :
if (!req.params.user_name) {
req.params.user = req.me;
} else {
User.findOne({username: req.params.user_name}, '_id', (error, user) => {
if (error) {
return next(error);
}
if (!user) {
let error = new Error('User not found');
return next(error);
}
req.params.user = user;
});
}
Account.findOne({name: req.params.account_name, created_by: req.params.user})
.populate(['currency', 'created_by'])
.exec((err, account) => {
if (err) {
return next(err);
}
return res.send(account);
});
As you can see the problem is that in one case I just have a simple procedural action to do, in the other I have to query the database which is async, then I have to execute the code below. I can't just simply put the Account query in the callback of the User query because I don't need to execute User query all the time.
I've tried to find an answer here but the only results I've found are about executing one async task or another (ex: Working with promises inside an if/else).
Following the recommandations on this post I've thought about wrapping the code inside the if block in an anonymous function and do something like:
let get_user;
if (!req.params.user_name) {
let get_user = () => {req.params.user = req.me};
} else {
let get_user = User.findOne({username: req.params.user_name}, '_id', (error, user) => {
if (error) {
return next(error);
}
if (!user) {
let error = new Error('User not found');
return next(error);
}
req.params.user = user;
});
}
get_user().then(() => {
Account.findOne({name: req.params.account_name, created_by: req.params.user})
.populate(['currency', 'created_by'])
.exec((err, account) => {
if (err) {
return next(err);
}
return res.send(account);
});
});
But I find it weird and I guess I would need to return a Promise from the anonymous function in the if block.
So what would be an elegant way of solving this ? I'm learning node.js on my free time and any general suggestions would be greatly appreciated.
Thanks for your time.
Callbacks shouldn't be used with Mongoose; it has been supporting promises for a long time.
This
let get_user = () => {req.params.user = req.me};
won't work because get_user is expected to return a promise.
It's usually done like:
let userPromise;
if (!req.params.user_name) {
userPromise = Promise.resolve(req.me);
} else {
userPromise = User.findOne(...);
}
userPromise().then((user => {
req.params.user = user;
return Account.findOne(...);
});
Notice that req.params.user is common code for both conditions. This is conveniently done with async..await, which is syntactic sugar for promises:
try {
let user;
if (!req.params.user_name) {
user = req.me;
} else {
user = await User.findOne({username: req.params.user_name}, '_id');
}
req.params.user = user;
const account = await Account.findOne({name: req.params.account_name, created_by: req.params.user})
.populate(['currency', 'created_by'])
.exec();
res.send(account);
} catch (err) {
next(err);
}
This is supposed to be a body of async middleware function, which wasn't shown in original code.
As explained in this answer, Express doesn't support promises itself, all async middlewares and route handlers should be wrapped with try..catch for error handling.

Using async await properly in node js

To overcome callback hell in javascript, I'm trying to use async await from legacy code written in SQLServer procedure.
But I'm not sure my code might be write properly.
My first confusing point is when async function returns, should it return resolve() as boolean, or just return reject and handle with try-catch?
Here is my code snippets.
Please correct me to right direction.
apiRoutes.js
app.route('/api/dansok/cancelDansok')
.post(dansokCancelHandler.cancelDansok);
dansokCancelController.js
const sequelize = models.Sequelize;
const jwt = require('jsonwebtoken');
async function jwtAccessAuthCheck(accessToken) {
if (!accessToken) {
return Promise.reject('Empty access token');
}
jwt.verify(accessToken,"dipa",function(err){
if(err) {
return Promise.reject('TokenExpiredError.');
} else {
return Promise.resolve();
}
});
}
async function checkFeeHist(dansokSeqNo) {
let feeHist = await models.FeeHist.findOne({
where: { DansokSeqNo: dansokSeqNo}
});
return !!feeHist;
}
async function getNextDansokHistSerialNo(dansokSeqNo) {
....
}
async function getDansokFee(dansokSeqNo) {
....
}
async function doCancel(dansokSeqNo) {
try {
if (await !checkFeeHist(dansokSeqNo)) {
log.error("doCancel() invalid dansokSeqNo for cancel, ", dansokSeqNo);
return;
}
let nextDansokSerialNo = await getNextDansokHistSerialNo(dansokSeqNo);
await insertNewDansokHist(dansokSeqNo, nextDansokSerialNo);
await updateDansokHist(dansokSeqNo);
await updateVBankList(dansokSeqNo, danokFee.VBankSeqNo);
await getVBankList(dansokSeqNo);
} catch (e) {
log.error("doCancel() exception:", e);
}
}
exports.cancelDansok = function (req, res) {
res.setHeader("Content-Type", "application/json; charset=utf-8");
const dansokSeqNo = req.body.DANSOKSEQNO;
const discKindCode = req.body.HISTKIND;
const worker = req.body.PROCWORKER;
const workerIp = req.body.CREATEIP;
const accessToken = req.headers.accesstoken;
//check input parameter
if (!dansokSeqNo || !discKindCode || !worker || !workerIp) {
let e = {status:400, message:'params are empty.'};
return res.status(e.status).json(e);
}
try {
jwtAccessAuthCheck(accessToken)
.then(() => {
log.info("jwt success");
doCancel(dansokSeqNo).then(() => {
log.info("cancelDansok() finish");
res.status(200).json({ message: 'cancelDansok success.' });
});
});
} catch(e) {
return res.status(e.status).json(e);
}
};
You'll need to rewrite jwtAccessAuthCheck(accessToken) so that it keeps track of the outcome of its nested tasks. In the code you've written:
// Code that needs fixes!
async function jwtAccessAuthCheck(accessToken) {
// This part is fine. We are in the main async flow.
if (!accessToken) {
return Promise.reject('Empty access token');
}
// This needs to be rewritten, as the async function itself doesn't know anything about
// the outcome of `jwt.verify`...
jwt.verify(accessToken,"dipa",function(err){
if(err) {
// This is wrapped in a `function(err)` callback, so the return value is irrelevant
// to the async function itself
return Promise.reject('TokenExpiredError.');
} else {
// Same problem here.
return Promise.resolve();
}
});
// Since the main async scope didn't handle anything related to `jwt.verify`, the content
// below will print even before `jwt.verify()` completes! And the async call will be
// considered complete right away.
console.log('Completed before jwt.verify() outcome');
}
A better rewrite would be:
// Fixed code. The outcome of `jwt.verify` is explicitly delegated back to a new Promise's
// `resolve` and `reject` handlers, Promise which we await for.
async function jwtAccessAuthCheck(accessToken) {
await new Promise((resolve, reject) => {
if (!accessToken) {
reject('Empty access token');
return;
}
jwt.verify(accessToken,"dipa",function(err){
if(err) {
reject('TokenExpiredError.');
} else {
resolve();
}
});
});
// We won't consider this async call done until the Promise above completes.
console.log('Completed');
}
An alternate signature that would also work in this specific use case:
// Also works this way without the `async` type:
function jwtAccessAuthCheck(accessToken) {
return new Promise((resolve, reject) => {
...
});
}
Regarding your cancelDansok(req, res) middleware, since jwtAccessAuthCheck is guaranteed to return a Promise (you made it an async function), you'll also need to handle its returned Promise directly. No try / catch can handle the outcome of this asynchronous task.
exports.cancelDansok = function (req, res) {
...
jwtAccessAuthCheck(accessToken)
.then(() => {
log.info("jwt success");
return doCancel(dansokSeqNo);
})
.then(() => {
log.info("cancelDansok() finish");
res.status(200).json({ message: 'cancelDansok success.' });
})
.catch(e => {
res.status(e.status).json(e);
});
};
I strongly suggest reading a few Promise-related articles to get the hang of it. They're very handy and powerful, but also bring a little pain when mixed with other JS patterns (async callbacks, try / catch...).
https://www.promisejs.org/
Node.js util.promisify

Resources