Throwing errors using async/await in AWS Lambda node.js function - javascript

I am trying to throw an error to the calling function and the error is not getting captured. The exception is not propagating to the calling function.
'use strict';
const { Pool } = require('pg');
const pool = new Pool();
var result;
exports.handler = async (event) => {
var payload = event;
try{
result = await insertOrder(payload, 'test');
}
catch (err) {
console.error("Error from main: " + err);
throw err ;
}
return result;
};
async function insertOrder(payload, name)
{
const client = await pool.connect();
try{
const queryString = {
text: "INSERT INTO public.orders(payload, shop_name)" +
"VALUES ($1, $2) RETURNING id",
values: [payload, name],
};
const result = await client.query(queryString);
var orderId = result.rows[0].id;
}
catch (err) {
await client.query('ROLLBACK');
console.log("Error from child: " + err);
throw err;
}
finally {
client.release();
return orderId;
}
}
Here is what is written to the log:
INFO Error from child: error: INSERT has more target columns than expressions
The console.error in the calling function is not written to the log. What am I am missing? TIA!

Moving return orderId; to try block solved my issue

Related

Nodejs api structure on calling sql helpers inside another helper all called by a controller

I'm studying to create a simple API with mysql. I've understood and implemented the simple structure in which the app call the router, that call the controller, that call the service. But now i'm developing a multiple tag service module and I've realized that I need to call the same sql queries services declared in it. I show you the code for a better understanding:
tag_service.js:
const mysql = require("../../config/database");
module.exports = {
insertTags: async (data, callBack) => {
const connection = await mysql.connection();
let results = '';
const tagsArray = data.tags.map(tag => [data.id_manager,data.cod_table,data.id_record,tag])
try {
//console.log("at insertCallout...");
await connection.query("START TRANSACTION");
results = await connection.query(
`INSERT INTO s_com_tags (id_manager,cod_table,id_record,tag)
VALUES (?,?,?)`,
[tagsArray]
);
await connection.query("COMMIT");
} catch (err) {
await connection.query("ROLLBACK");
//console.log('ROLLBACK at insertCallout', err);
throw err;
} finally {
await connection.release();
return callBack(null, results);
}
},
deleteTags: async (data, callBack) => {
//console.log(data);
let results = '';
const connection = await mysql.connection();
try {
//console.log("at deleteCallouts...");
await connection.query("START TRANSACTION");
results = await connection.query(
`DELETE FROM s_com_tags
WHERE cod_table = ? AND id_record = ? AND tag IN (?)`,
[data.code_table, data.id_record,data.tags]
);
//console.log(res);
await connection.query("COMMIT");
} catch (err) {
await connection.query("ROLLBACK");
//console.log('ROLLBACK at deleteCallouts', err);
throw err;
} finally {
await connection.release();
return callBack(null, Callouts);
}
},
};
controller's structure that will use the service:
module.exports = {
updateLabDesc: async (req, res, next) => {
try {
const body = req.body;
if(!body.internal_code){
updateLabDesc(body.manager, async (err, results) => {
if (err) {
return next(createError.InternalServerError())
}
});
}
updateTags(body, async (err, results) => {
if (err) {
return next(createError.InternalServerError())
}
return res.json({
success: (results ? 1 : 0 ),
message: (results || 0) + " LabDesc inserted successfully"
});
});
} catch (error) {
next(error)
}
},
};
But the update is something like
updateTag function => {
try {
const current_tags = await getTags(req.body);
let newTags = [];
let oldTags = [];
req.body.tags.forEach(tag => {
if(!current_tags.includes(tag))
newTags.push(tag)
});
await insertTags(newTags);
current_tags.tags.forEach(tag => {
if(!req.body.tags.includes(tag))
oldTags.push(tag)
});
await deleteTags(oldTags);
} catch (error) {
next(error)
}
},
Basically, the tag_service has insertTags and deleteTags but I need the updateTags to call these functions as well. The final controller will call insertTags, deleteTags and updateTags. How can I structure these calls?
It is a controller that could call 2 helpers (insertTag and deleteTags) and another helper (updateTags) that call these 2 helpers. Any ideas?

JEST Testing try catch - get the error message

I'm trying to test the error handling portion of my function but I am not sure how to do this... I am using someone's API that is always running, so how can I simulate the API not connecting?
async function getElephant() {
const proxyurl = 'https://cors-anywhere.herokuapp.com/'
const url = 'https://elephant-api.herokuapp.com/elephants/random'
fetch(proxyurl + url)
.then((resp) => { return resp.json() })
.then((data) => {
data.forEach((elephant) => {
const { name, sex, species, note } = elephant
document.getElementById('name').value = name
document.getElementById('gender').value = sex
document.getElementById('species').value = species
document.getElementById('about').value = note
})
})
// .catch(() => console.log("Can't access " + url + " blocked?"))
.catch(() => ("Can't access"))
}
My test:
test('Test .catch block, failure message to connect to url', async () => {
expect.assertions(1);
return expect(getElephant()).rejects.toEqual('Can't access');
})
and also tried using fetch-mock utility
test('Test .catch block, failure message to connect to url', async () => {
const url = 'https://lephant-api.herokuapp.com/elephants/random'; //Try misspelling url to catch error
fetchMock.get(url, {
status: 400,
body: JSON.stringify('BAD CONNECTION')
})
const response = await getElephant(url)
const result = await response.json()
expect(result).toThrow("Can't access")
})
Any advice is appreciated!
I hope this example helps you how to handle errors with try catch
function addTask() {
x = "test input";
try {
if(x == "") throw "empty"; // error cases
if(isNaN(x)) throw "not a number";
x = Number(x);
if(x > 10) throw "too high";
}
catch(err) { // if there's an error
console.error("Input is " + err); // write the error in console
}
finally { // Lets you execute code, after try and catch, regardless of the result
console.log("Done");
}
}
addTask();

How can integrate multiple functions into my post route and pass on objects

I want to integrate the Stripe api with my project. I am already collecting all needed data and sending it to my post route.
I want to make charges to a customer and have all functions to do so, if I would invoke them all one by one. How can I integrate all functions into my post route, so it is processed all at once. Also, I do not how to pass data from one function to another, so in the end there would be a function chain with the same data. My post route and functions:
router.post("/checkout", async function (req, res, next) {
if (!req.session.cart) {
return res.redirect("/shopping-cart");
}
// You can return promise directly
let createCustomer = function () {
var param ={};
param.email = req.body.email;
param.name= req.body.name;
param.description ="";
return stripe.customers.create(param, function (err, customer) {
if (err) {
console.log("err:" + err);
}
if (customer) {
console.log("success: " + JSON.stringify(customer, null, 2));
} else {
console.log("something went wrong");
}
});
};
let createToken = function () {
let param ={};
param.card = {
number: req.body.card,
exp_month: req.body.exp_month,
exp_year: req.body.exp_year,
cvc: req.body.security
}
return stripe.tokens.create(param, function (err, token) {
if (err) {
console.log("err:" + err);
console.log(param);
}
if (token) {
console.log("success: " + JSON.stringify(token, null, 2));
console.log(req.body);
} else {
console.log("something went wrong");
}
});
};
let addCardToCustomer = function () {
console.log(createdCustomer);
return stripe.customers.createSource(customer.id, {source: token.id}, function (err, card) {
if (err) {
console.log("err:" + err);
console.log(param);
}
if (card) {
console.log("success: " + JSON.stringify(card, null, 2));
} else {
console.log("something went wrong");
}
});
};
try {
const createdCustomer = await createCustomer(); // promise 1
const createdToken = await createToken();
const addedCardToCustomer = await addCardToCustomer(createdCustomer,createdToken ); // await addCardToCustomer(createdCustumer); to pass created customer info to next request
// const chargeCustomerThroughCustomerID = await chargeCustomerThroughCustomerID(); // promise 3
// more things...
res.send("success");
} catch (e) {
console.log(`error ${e}`)
};
});
you can chain your promises... / use async await and do one task at time in order you need. you can also pass data from one promise to another as shown below.
// You can return promise directly
let createCustomer = function () {
return stripe.customers.create(param);
}
let addCardToCustomer = function(){
return stripe.customers.createSource(customer.id,{source:token.id});
};
// or use async /await
let chargeCustomerThroughCustomerID = async function () {
const data = await stripe.charges.create(param).catch((e) => { console.log(`error ${e}`); throw e })
// do something with data
return data;
}
let chargeCustomerThroughTokenID = async function () {
const data = await stripe.charges.create(param).catch((e) => { console.log(`error ${e}`); throw e });
// do something with data
return data;
}
router.post("/checkout", async function(req, res, next) { // Async
if (!req.session.cart) {
return res.redirect("/shopping-cart");
}
var cart = new Cart(req.session.cart);
try {
const createdCustumer = await createCustomer(); // promise 1
const addCardToCustomer = await addCardToCustomer(); // await addCardToCustomer(createdCustumer); to pass created customer info to next request
const chargCustomer = await chargeCustomerThroughCustomerID(); // promise 3
// more things...
res.send(...);
}
catch(e) {
console.log(`error ${e}`)
}
});

Node js lamba not waiting for db event to finish

I have a lambda function which connect to MySQL and stream data to aws sqs, this code runs fine in local but when ran in lambda the function terminate before publishing event to sqs , lambda in not waiting for event loop to finish.
following is the code.
exports.handler = async (event,context) => {
return new Promise((resolve,reject)=>{
context.callbackWaitsForEmptyEventLoop = true;
console.log("running handler");
query().then((message)=>{
console.log("sucess++++ " + message);
resolve(message);
},(error)=>{
console.log("Error++ " + error);
reject(error);
});
})
};
function query() {
logger.info("inside query()");
return new Promise((resolve,reject)=>{
try {
connection = mysql.createConnection({
host: HOST,
user: USER,
password: PASSWORD,
port: PORT
});
const dateObject = getDateObject();
console.log('dateobject ' + dateObject);
let sql = fs.readFileSync('./sql/test.sql').toString();
const finalSql = sql.replace(/{dateString}/g, dateObject);
// logger.info("running query " + finalSql);
console.log(finalSql);
var query = connection.query(finalSql);
query
.on('error', async function (err) {
logger.error("error while running query " + err);
reject(err);
})
.on('fields', function (fields) {
})
.on('result', async function (row) {
// connection.pause();
await processRow(row);
})
.on('end', async function () {
logger.info("all rows have been received");
//logger.info("closing connections");
resolve("sucesss");
connection.end();
});
}
catch (error) {
console.log(error);
logger.error(error);
}
})
}
// };
async function processRow(row) {
await sendMessage(row);
}
function getDateObject() {
//return dateObj;
}
async sendMessage(message) {
let messageBody = {};
messageBody['Subject']="xyz";
messageBody['Message']= JSON.stringify(message);
var params = {
DelaySeconds: 0,
QueueUrl: SQS_URL,
MessageBody: JSON.stringify(messageBody)
}
this.sqs.sendMessage(params, function (err, data) {
if (err) {
logger.error("Error" + err);
} else {
logger.info("Success" + data.MessageId);
}
});
}
Earlier I tried with async await instead of promise but stills it doesn't work as expected
the result I get is
sucess++++ sucesss
and it terminate after that without publishing the message.
If I use timeout() in the handler and make the function wait then it works fine.
any reason why it doesn't work.

neo4j cypher will not update database

following code gets error "result undefined" (last error trap) please help:
try {
var driver = neo4j.driver("bolt://localhost:7474", neo4j.auth.basic(userName, passWord));
} catch (err) {
alert(err.message);
}
const session = driver.session();
const personName = 'Alice';
try {
const resultPromise = session.run('CREATE (a:Person {name: $name}) RETURN a', {
name: personName
});
} catch (err) {
alert(err.message);
}
try {
resultPromise.then(
result => {
session.close();
const singleRecord = result.records[0];
const node = singleRecord.get(0);
console.log(node.properties.name);
driver.close();
}
);
} catch (err) {
alert(err.message);
}
I think the error is due to the fact that you are using the java bolt driver on the http port (7474) of Neo4j.
Just change the connection url by this one : neo4j.driver("bolt://localhost:7687", neo4j.auth.basic(userName, passWord))

Categories