How to handle errors with Async and Await [Node.js] - javascript

I have already a function written with bluebird promises and I would like to rewrite it with async and await. When I have made the changes I have found out that earlier with promises the reject statement always transfers the control to called function catch block though if the catch block is already there in the file from where we are rejecting. How to handle this situation properly with async and await?. (Added comments to the code to explain the issue)
With Promise:
const callingFunc = (req, res) => {
return new Promise((resolve, reject) => {
// execute request which returns promise
functionCall()
.then((response) => {
let error;
try {
xml2js(response.body, { explicitArray: false }, (err, result) => {
if (err) {
return reject(err); /* throws the correct error to catch block of the file from where callingFunc is called*/
}
if (!_.isEmpty(result.Response.errorCode)) {
return reject(result.Response); /* throws the correct error to the catch block of the file from where callingFunc is called*/
}
return resolve(result);
});
} catch (e) {
error = new Error('xml2js conversion error');
reject(error);
}
})
.catch((error) => {
const Error = new Error('Internal Server Error');
reject(Error);
});
});
};
With async and await:
const callingFunc = (req, res) => {
try {
const response = await functionCall();
let error;
try {
xml2js(response.body, { explicitArray: false }, (err, result) => {
if (err) {
throw (err); /* throws the error to the below catch block and returning xml2js conversion error and changing behaviour*/
}
if (!_.isEmpty(result.Response.errorCode)) {
throw result.Response; /* throws the error to the below catch block and returning xml2js conversion error and changing behaviour*/
}
return result;
});
} catch (e) {
error = new Error('xml2js conversion error');
throw error;
}
} catch(error) {
const Error = new Error('Internal Server Error');
throw Error;
}
};

If functionCall returns a promise, then this code is inappropriate...
return new Promise((resolve, reject) => {
// execute request which returns promise
functionCall()
.then((response) => {
If xml2js is async using callbacks, then it is appropriate to wrap it in a promise...
// return a promise that resolves with the result of xml2js
async function xml2js_promise(body) {
return new Promise((resolve, reject) => {
xml2js(body, { explicitArray: false }, (err, result) => {
if (err) reject(err);
else if (!_.isEmpty(result.Response.errorCode)) reject(result.Response);
else resolve(result);
});
});
}
Now we can await these. There's no need to nest the try's. (And you only need the try if you're going to do something on the catch).
async callingFunction = (req, res) => {
try {
const response = await functionCall();
} catch (error) {
// do something with this error
}
try {
const result = await xml2js_promise(response.body)
} catch(error) {
// do something with this error
}
return result;
}

Related

Should i use promise or callback in the following code?

I have some routes
routes.js
var express = require("express");
var router = express.Router();
const { controllerMethod1, controllerMethod2 } = require("./controller");
router.get("/route1", controllerMethod1);
router.get("/route2", controllerMethod2);
module.exports = router;
if i use promise variable as global,
its used by all method in controller.js.
should i use global or local variable for promise ?
controller.js
const {
serviceMethod1,
serviceMethod2,
serviceMethod1ByDate,
} = require("./services");
let promise; //global promise variable
const controllerMethod1 = (req, res) => {
//let promise; local promise variable
//This is for Callback
if (req.query.date) {
serviceMethod1ByDate(req.query.date, (err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
} else {
serviceMethod1((err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
}
// This is for Promise
promise = req.query.date
? serviceMethod1ByDate(req.query.date)
: serviceMethod1();
Should i use way 1 or way 2 ?
if multiple users request one or more routes at the same time,can handleResponse method work correctly?
Way 1 for promise
promise
.then((results) => {
return res.json({
status: "success with promise variable",
data: results,
});
})
.catch((error) => {
return res.status(500).json({
status: "error with promise variable",
message: "there is no person details",
});
});
Way 2 for Promise
handleResponse(promise, res);
//this method is working for all routes when i use promise
const handleResponse = (results, response) => {
results
.then((result) => {
return response.json({
status: "success with promise variable in handleResponse",
data: result,
});
})
.catch((error) => {
return response.status(500).json({
status: "error with promise variable handleResponse",
message: "Internal Server Error",
});
});
};
controller.js
const controllerMethod2 = (req, res) => {
//------------------ Using Callback Method -------------
serviceMethod2((err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
//------------------ Using Promise Method -------------
//local variable
let promise;
promise = serviceMethod2();
//Way 1 for Promise
promise
.then((result) => {
//...
})
.catch((err) => {
//...
});
//Way 2 for Promise
handleResponse(promise, res);
};
module.exports = { controllerMethod1, controllerMethod2 };
service.js
const pool = require("../../../config/database");
//-----------------------Using Callback Mehthod----------------
const serviceMethod1 = async (CallBack) => {
let query = "select * from databse";
await pool.query(query, [], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
};
const serviceMethod1ByDate = async (date) => {
let query = "select * from databse where date ?";
return await new Promise((resolve, reject) => {
pool.query(query, [date], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
});
};
const serviceMethod2 = async (Callback) => {
let query = "select * from database";
await pool.query(query, [], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
};
//-----------------------Using Promise Method----------------
const serviceMethod1 = async () => {
let query = "select * from databse";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
const serviceMethod1ByDate = async (date) => {
let query = "select * from databse where date ?";
return await new Promise((resolve, reject) => {
pool.query(query, [date], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
const serviceMethod2 = async () => {
let query = "select * from database";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
module.exports = {
serviceMethod1,
serviceMethod1ByDate,
serviceMethod2,
};
if i use promise variable as global, its used by all method in controller.js. should i use global or local variable for promise ?
You should use local variable for this type of operation as global variable are generally used to define constants or methods. They cannot be used as temporary values because it's value can be changed anytime and that'll result in conflict with other functionalities and so must be avoided.
Should i use way 1 or way 2 ? if multiple users request one or more routes at the same time,can handleResponse method work correctly?
Way 2 is more efficient that Way 1 because if you use way 1 then you will have to do it for every method in the controller. Way 2 is like a common method where you can format your response and most of the developers use it.
It doesn't make any difference whether you use callbacks or promises but just a clean way to do things.
Instead of using this:
const serviceMethod1 = async () => {
let query = "select * from databse";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
Use this:
// Remove the async await from here and handle the response/error where the below method is called by putting it in try catch block.
const serviceMethod1 = () => {
let query = "select * from databse";
return new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
// otherFile.js
someMethod = async () => {
try {
const result = await serviceMethod1();
// handle the response
} catch {
// handle the error
}
}

Connection is not defined in oracledb

I am using the oracledb cen node.js module and when making a database connection to make a select, it returns the data but this error also appears:
(node:1) UnhandledPromiseRejectionWarning: ReferenceError: connection is not defined
at Object.getTest (/home/src/storage/oracleDb.js:29:9)
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().
(rejection id: 1)
(node:1) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I do the query like this:
try {
await oracledb.getConnection(config.db)
.then(function (conn) {
return conn.execute(querys.queryTest());
}, function(err) {
console.log(err);
})
.then(function (result) {
console.log('Query executed');
console.log(result.rows[0]);
}, function(err) {
console.log(err);
})
.catch(function(err) {
console.log(err);
});
} catch (error) {
console.log(error);
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
If you can use await, then you're in an async function. If you're in an async function, why are you using promise chains?
Here's what this type of code would look like with Promises:
const oracledb = require('oracledb');
function getEmployee(empId) {
return new Promise(function(resolve, reject) {
let conn; // Declared here for scoping purposes.
oracledb
.getConnection()
.then(function(c) {
console.log('Connected to database');
conn = c;
return conn.execute(
`select *
from employees
where employee_id = :emp_id`,
[empId],
{
outFormat: oracledb.OBJECT
}
);
})
.then(
function(result) {
console.log('Query executed');
resolve(result.rows[0]);
},
function(err) {
console.log('Error occurred', err);
reject(err);
}
)
.then(function() {
if (conn) {
// If conn assignment worked, need to close.
return conn.close();
}
})
.then(function() {
console.log('Connection closed');
})
.catch(function(err) {
// If error during close, just log.
console.log('Error closing connection', err);
});
});
}
module.exports.getEmployee = getEmployee;
And here's what it would look like with async/await:
const oracledb = require('oracledb');
function getEmployee(empId) {
return new Promise(async function(resolve, reject) {
let conn; // Declared here for scoping purposes.
try {
conn = await oracledb.getConnection();
console.log('Connected to database');
let result = await conn.execute(
`select *
from employees
where employee_id = :emp_id`,
[empId],
{
outFormat: oracledb.OBJECT
}
);
console.log('Query executed');
resolve(result.rows[0]);
} catch (err) {
console.log('Error occurred', err);
reject(err);
} finally {
// If conn assignment worked, need to close.
if (conn) {
try {
await conn.close();
console.log('Connection closed');
} catch (err) {
console.log('Error closing connection', err);
}
}
}
});
}
module.exports.getEmployee = getEmployee;
See this series for more info:
https://jsao.io/2017/06/how-to-get-use-and-close-a-db-connection-using-various-async-patterns/
You can try add connection to a variable declared outside try-catch block, something like below:
let connection;
try {
await oracledb.getConnection(config.db)
.then(function (conn) {
// this is where you assign the connection value to a variable
connection = conn;
return conn.execute(querys.queryTest());
}, function(err) {
console.log(err);
})
.then(function (result) {
console.log('Query executed');
console.log(result.rows[0]);
}, function(err) {
console.log(err);
})
.catch(function(err) {
console.log(err);
});
} catch (error) {
console.log(error);
} finally {
// this if should be fine now
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
I would suggest to read about scoping in javascript, it might help you for future problems. Here's a link: https://www.w3schools.com/js/js_scope.asp

How to handle API response errors in async/await

I'm trying to better understand error handling while using async/await, third party libs, and external APIs.
Given the following pseudo-code:
const createConnectionRequest = async (args) => {
try {
const { data } = axios.post(url, args);
return data;
} catch (err) {
throw new Error(err);
}
}
My understanding is the throw would occur a result of the axios.post failing rather than an issue with my request.
If the response from my API was 200 but included an error of some sort, eg.
{
status: 200,
error: 'Invalid fields supplied',
}
Would I throw this error in the try block and expect a parent calling function to catch it?
const createConnectionRequest = async (args) => {
try {
const { data } = axios.post(url, args);
if (data.error) {
throw new Error(data.error);
}
return data;
} catch (err) {
throw new Error(err);
}
}
...
const processor = async () => {
try {
await createConnectionRequest(...);
} catch (err) {
// handle error from API response here
throw new Error(err);
}
}

How to get values from a inner function in nodejs

HI HAVE A SIMPLE FUNCTION WHICH TAKE A NUMBER AND VERIFY IT
var verifyNumber =(phoneNumber)=>{
//Number Verification
cb.validatePhone(phoneNumber,'sms',(err,data)=>{
if(err){
console.log(`You got an error `);
}
console,log('Code send');
return data
})
}
verifyNumber('***********');
but the problem is that i want the response which the cb.validatePhone() is given back which is in the 2nd param (data)
and when i return it gave me "undefined" :(
so you can a get the data which is a Object .
There are a number of ways to return data from an async operation.
Here's an example using a callback:
function verifyNumber(phoneNumber, callback) {
try {
cb.validatePhone(phoneNumber, 'sms', (err, data) => {
if (err) throw new Error('You got an error');
callback(data);
});
} catch (e) {
console.log(e);
}
}
verifyNumber('***********', (data) => console.log(data));
Here's one using a promise.
function verifyNumber(phoneNumber) {
return new Promise((resolve, reject) => {
try {
cb.validatePhone(phoneNumber, 'sms', (err, data) => {
if (err) throw new Error('You got an error');
resolve(data);
});
} catch (e) {
console.log(e);
}
});
}
verifyNumber('***********').then(data => console.log(data));

How can I catch rejected Promises?

My code is as follows:
errorTest().then((result) => {
try {
console.log(result);
}
catch (err) {
console.error("Error detected 1");
console.error(err);
}
}).catch((err) => {
console.error("Error detected 2");
console.error(err);
});
async function errorTest() {
return new Promise((resolve, reject) => {
reject("my error");
})
}
Currently, it prints "Error detected 2".
I would like to catch my error using try / catch such that the code prints "Error detected 1".
How do I modify my code to do this?
first when you declare async function that means you declare a function that returns a Promise. so you don't need to warp it with new Promise
you can just do
async function errorTest() {
throw new Error("my error")
}
then you can catch it with try catch like this
(async () =>{
try{
await errorTest()
}
catch(err){
console.log(err)
}
})()
then the full code will look like this
async function errorTest() {
throw new Error("my error")
}
(async () =>{
try{
await errorTest()
}
catch(err){
console.log(err)
}
})()
The problem is that an error is being thrown in the errorTest function, which happens first, that means that the .catch function is called instead of .then.
async function errorTest() {
return new Promise((resolve, reject) => {
reject("my error");
})
}
try {
var result = await errorTest()
try {
console.log(result);
} catch (err) {
console.error("Error detected 2");
console.error(err);
}
} catch (err) {
console.error("Error detected 1");
console.error(err);
}
you can do something like this
//no need to make it async
function errorTest() {
return new Promise((resolve, reject) => {
reject("my error");
})
}
async function test(){
try{
await errorTest();
try{
console.log(result);
//try some syncronous task.
}
catch(e){
console.error("Error detected 1");
console.error(err);
}
}
catch(err){
//if promise returned by errorTest() is rejected; rejected value: err
console.error("Error detected 2");
console.error(err);
}
}
test(); //this also returns a promise though.
Hope, this helps.

Categories

Resources