Node JS + AWS Promise Triggered Twice - javascript

AWS = require('aws-sdk');
AWS.config.region = 'eu-west-1';
ses = new AWS.SES();
var params = {};
return ses.sendEmail(params, function (err, data) {
console.log('----->sending email')
}).promise().then((data) => {
console.log('---->sending promise')
}).catch((err) => {
console.log('----->am in error')
console.log(err)
})
Can someone help my above code promise is triggered twice.
I should get below
----->sending email
---->sending promise
But i got
----->sending email
---->sending promise
----->sending email

It looks like you are providing both a callback function and using the promise approach. Effectively, this means that you have two different functions that execute when the request is done. Choose one of the following:
You can use the promise approach, with then and catch.
function send(params) {
ses.sendEmail(params).promise().then((data) => {
console.log('Email was sent')
}).catch((err) => {
console.log('There was an error')
})
}
You can use promise with async/await. Make sure you add the async keyword to your function header. Make sure your Node runtime supports async/await or that you code is transpiled to whatever Node version you are using.
async function send(params) {
try {
const data = await ses.sendEmail(params).promise();
console.log('Email was sent')
} catch(err) {
console.log('There was an error')
}
}
Finally, you could use the callback approach:
function send(params) {
ses.sendEmail(params, function(err, data) {
if (err) {
console.log('There was an error')
return
}
console.log('Email was sent')
})
}

Related

Express email error handling, for nested middleware

I have an express route for handling password resets, and with that i have a route, where i first find the user, and have some error handling with that, but now i want aditional error handling inside a nested function, and I'm not sure what pattern to use
function triggerPasswordResetEmailSend(req, res, next) {
var email = req.body.email;
if (!email) return res.status(422).json({error: "Please provide an email."});
UserRepositoryClass.findUserByEmail(email).then(user =>{
if(!user) return res.status(422).json({message: "User not found"})
sendPasswordReset(user);
return res.status(200).json({user: user});
}).catch(err =>{
return res.status(500).json({error: err})
});
}
Inside this function i do some initial error handling. The issue now is that the sendPasswordReset function can also throw errors, but there are not caught by the .catch() function, so I'm looking for something to handle this function.
I have tried passing the req and res objects into the function, but that does not seem like a good solution. I could do some try catch or maybe return a promise. But i want to ensure, that i follow the same pattern and best practises as i have already tried to do.
Here is the code snippet from my mail function:
module.exports = (user) => {
const userResetToken = generatePasswordToken();
UserRepositoryClass.setPasswordResetToken(user.id, userResetToken);
const passwordResetUrl = PASSWORD_RESET_URL(user._id, userResetToken);
return sendMail(options(user.email, passwordResetUrl));
}
You can use promise instead of function.
module.exports.sendPasswordReset = user = new Promise((resolve, reject) => {
const userResetToken = generatePasswordToken();
UserRepositoryClass.setPasswordResetToken(user.id, userResetToken);
const passwordResetUrl = PASSWORD_RESET_URL(user._id, userResetToken);
sendMail(options(user.email, passwordResetUrl))
.then(response => {
resolve(response, null); // we can get result as (data,error) here error is null
})
.catch(err => {
reject(null, err); // here response is null
});
});
You can use sendPasswordReset Promise like this:
sendPasswordReset(user).then((res, err) => {
// here you can get your res as well as err
if (err) throw new Error("Error while sending an email");
console.log("response", res);
});

NodeJS NPM soap - how do I chain async methods without callbacks (ie use async or Promise)?

I have successfully called a sequence of soap webservice methods using nodejs/javascript, but using callbacks... right now it looks something like this:
soap.createClient(wsdlUrl, function (err, soapClient) {
console.log("soap.createClient();");
if (err) {
console.log("error", err);
}
soapClient.method1(soaprequest1, function (err, result, raw, headers) {
if (err) {
console.log("Security_Authenticate error", err);
}
soapClient.method2(soaprequest2, function (err, result, raw, headers) {
if (err) {
console.log("Air_MultiAvailability error", err);
}
//etc...
});
});
});
I'm trying to get to something cleaner using Promise or async, similar to this (based on the example in the docs here https://www.npmjs.com/package/soap) :
var soap = require('soap');
soap.createClientAsync(wsdlURL)
.then((client) => {
return client.method1(soaprequest1);
})
.then((response) => {
return client.method2(soaprequest2);
});//... etc
My issue is that in the latter example, the soap client is no longer accessible after the first call and it typically returns a 'not defined' error...
is there a 'clean' way of carrying an object through this kind of chaining to be used/accessible in subsequent calls ?
Use async/await syntax.
const soap = require('soap');
(async () => {
const client = await soap.createClientAsync(wsdlURL);
cosnt response = await client.method1Async(soaprequest1);
await method2(soaprequest2);
})();
Pay attention to Async on both createClient and method1
In order to keep the chain of promises flat, you can assign the instance of soap to a variable in the outer scope:
let client = null;
soap.createClientAsync(wsdlURL)
.then((instance) => {
client = instance
})
.then(() => {
return client.method1(soaprequest2);
})
.then((response) => {
return client.method2(soaprequest2);
});
Another option would be nested chain method calls after the client is resolved:
soap.createClientAsync(wsdlURL)
.then((client) => {
Promise.resolve()
.then(() => {
return client.method1(soaprequest2);
})
.then((response) => {
return client.method2(soaprequest2);
});
})

Return value from callback function in AWS Javascript SDK

I'm using the AWS Javascript SDK and I'm following the tutorial on how to send an SQS message. I'm basically following the AWS tutorial which has an example of the sendMessage as follows:
sqs.sendMessage(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.MessageId);
}
});
So the sendMessage function uses a callback function to output whether the operation was successful or not. Instead of printing to the console I want to return a variable, but every value I set is only visible within the callback function, even global variables like window.result are not visible outside the callback function. Is there any way to return values outside the callback?
The only workaround I've found at the moment is to set a data attribute in an HTML element, but I don't think it's really elegant solution.
I would suggest to use Promises and the new async and await keywords in ES2016. It makes your code so much easier to read.
async function sendMessage(message) {
return new Promise((resolve, reject) => {
// TODO be sure SQS client is initialized
// TODO set your params correctly
const params = {
payload : message
};
sqs.sendMessage(params, (err, data) => {
if (err) {
console.log("Error when calling SQS");
console.log(err, err.stack); // an error occurred
reject(err);
} else {
resolve(data);
}
});
});
}
// calling the above and getting the result is now as simple as :
const result = await sendMessage("Hello World");

Javascript Promises : Can I know which part of promise chain caused error?

(Please excuse my English)
I am learning about javascript promises, now.
Below sample code is a simple javascript code for node.js(my node.js version is v10.0.0), which asynchronously reads and parses a JSON file using promise chain.
const fs = require("fs");
function readFileAsync(filename) {
return new Promise((resolve, reject) => {
fs.readFile(filename, 'utf8', (error, result) => {
if (error)
reject(error);
else
resolve(result);
});
});
}
readFileAsync('test.json')
.then(res => JSON.parse(res))
.then(res => { console.log('JSON=', res); })
.catch(err => { console.log(err.message); });
I found that this sample code generates different formats of error messages.
For example, if it cannot find 'test.json', the error message is...
ENOENT: no such file or directory, open '/home/node/test.json'
If it cannot parse 'test.json', the error message is...
Unexpected token / in JSON at position 31
I want to modify the sample code to generate same format of error message always containing JSON file name.
To do so, firstly I should know which part of promise chain caused error. How can I know?
There are two ways to arrived what you want.
Promise.then has two arguments, see below code and you can get more information here
readFileAsync('test.json')
.then(res => JSON.parse(res))
.then(res => { console.log('JSON=', res); }, error => {
// here can catch error of previous then function
});
Another way is modify the function readFileAsync
function readFileAsync(filename) {
return new Promise(resolve => {
fs.readFile(filename, (error, result) => {
if (error)
resolve(null); // you can resolve whatever you want
else
resolve(result);
});
});
}
And .catch() will not catch any error of readFileAsync.
Below sample code is a my solution. Thank you, Bergi and Stephen.
I choose this solution because I want to know exactly where in the chain the error occurred and what is the error.
const fs = require("fs");
function readFileAsync(filename) {
return new Promise((resolve, reject) => {
fs.readFile(filename, 'utf8', (error, result) => {
if (error)
reject(error);
else
resolve(result);
});
});
}
function readJsonAsync(filename, fnCallBack) {
function fnMessage(n, str) {
console.log(`[${n}:${filename}]`, str);
}
readFileAsync(filename)
.then(
res => JSON.parse(res),
err => { fnMessage(-1, err.message); }
).then(
res => {
// if some errors occured at the previous step, res === undefined
if (res !== undefined)
fnCallBack(filename, res);
},
err => { fnMessage(-2, err.message); }
);
}
function printJSON(filename, json) {
console.log(`JSON[${filename}]:`, json);
}
readJsonAsync('test.json', printJSON);
My solution has a prerequisite. The prerequisite is...
There is no simple way to break a promise chain even if some errors
occured at previous steps of the chain.
Is this prerequisite right?

Node js: Express js asynchronous db query execution-return results got undefiend

Just started to learn express js framework ,here is my simple database query execution part its invoked with this url localhost:3000/api/test.
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is:', results[0].id);
return results;
});
Does it really asynchronous?? suppose another user request this url does he need to wait for the previous query execution??.
I've heard about async package ,but don't know how this is applicable in my case
UPDATE
I got proper result in console.log(); but when i return the result i got undefined error
Here is my model.js
module.exports = {
getUser:function () {
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is: ', results[0].id);
});
}
}
From my controller.js
var model = require('../models/user.js');
module.exports = {
getData : function(req, res){
//invoke model
console.log(model.getUser());
}
}
Node is non-blocking and will serve this request as and when it's called.
If another user hits this endpoint then it will execute again regardless if the first query has completed or not (unless the SQL has locked the table, in which case all consecutive connections/queries will wait and may timeout because of it). This happens on a connection basis.
You should make sure to check your SQL server (MySQL?) configs here to make sure there are enough max_connections to be able to cope with whatever load you are expecting.
Remember that the biggest bottleneck to an application is usually the database.
Your query above will need a callback to return the data asynchronously.
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is:', results[0].id);
//cb=callback function passed in to context
if (cb) cb(results);
});
Updated answer from updated question
In your model.js:
module.exports = {
getUser:function (cb) {
db.query('SELECT * FROM user', function (error, results, fields) {
if (error) throw error;
console.log('The result is: ', results[0].id);
if (cb) cb(results);
});
}
}
In your controller.js:
module.exports = {
getData : function(req, res){
//invoke model
model.getUser(function(results) {
console.log(results);
});
}
}
When you deal with callback, the safe and clean way to handle them is Promises. It's now standard in JavaScript and don't require any module.
And yes it is asynchronous. Behind, there'll be network access and dialogs with the database server. Only when they're done chatting will the callback be called.
module.exports = {
getUser: function () {
// wrap asynchronously called callback in Promise
new Promise((resolve, reject) => {
db.query("SELECT * FROM user", (error, results, fields) => {
if (error) {
reject(error); // similar to "throw"
}
else {
resolve({ results, fields }); // similar to "return"
}
});
});
}
};
How do you use it:
Vanilla notation:
// similar to "try"
model.getUser()
.then((answer) => {
console.log("answer", answer);
})
// similar to "catch"
.catch((error) => {
console.log("error", error);
});
async-await notation (only available in last versions of nodejs & browsers):
// you must be in an async environement to use "await"
async function wrapper() {
try {
var answer = await model.getUser(); // wait for Promise resolution
console.log("answer", answer);
}
catch(error) {
console.log("error", error);
}
}
// async function return automatically a Promise so you can chain them easily
wrapper();

Categories