How to display a message? - node.js

At the moment, for example, when deleting a record using Postman, a hang occurs and no error is displayed there. How can immediately display this error in Postman if it appears?
module.exports.remove = async function (req, res) {
try {
let category = await SprCategories.findOne({ CATEGORY_ID: req.params.CATEGORY_ID })
category.destroy().then(() => {
res.status(200).json(category)
})
} catch (e) {
errorHandler(res, e)
}
}
errorHandler:
module.exports = (res, error) => {
res.status(500).json({
success: false,
message: error.message ? error.message : error
})
}

It looks like your Unhandled rejection Error is coming from category.destroy().
To solve this since you are already using an async funcion, await category.destroy() if it fails your catch block will take over
module.exports.remove = async function (req, res) {
try {
const category = await SprCategories.findOne({ CATEGORY_ID: req.params.CATEGORY_ID })
await category.destroy()
res.status(200).json(category)
} catch (e) {
errorHandler(res, e)
}
}

Related

Node.js: Function not awaiting for a promise

I'm having an issue with a function not awaiting for a promise.
I have a route with a post method, that pushes the body to the controller.
The controller, will then send it to the middleware to actually process the save to a MongoDB.
The middleware will return the the promised object back to the controller.
The controller is finishing with out awaiting the completion of the middleware.
The middleware is async, and the controller has an await and then a .then even following further.
Thoughts?
Controller
export async function createPlayer(req,res) {
//creates a Player in the database
try {
let results = '';
results = await PlayerFunction.createPlayer(req.body)
.then(console.log(results))
.then(res.status(200).send(results))
} catch (error) {
log_error('Errored trying to create Player in controller.', error);
res.status(404).send('Error Has Occured. An Admin has been contacted.');
}
};
Middleware
export async function createPlayer(req_body) {
//creates a Player in the database
try {
//set new player object
let new_Player = new Player(req_body);
new_Player.save((error) => {
if (error) {
log_error('Trying to create a Player.', error)
return { success: 'error', body: 'Error Has Occured. An Admin has been contacted.' };
} else {
console.log(new_Player);
return { success: true, body: new_Player };
};
});
} catch (error) {
log_error('Errored trying to create a player.', error);
return { success: 'error', body: 'Error Has Occured. An Admin has been contacted.' };
}
};
I tried to use .then promises to catch the returned results from the middleware and then return the results to the user.
What I have found is that the .save((error) => function doesn't follow the await made by the call it self. If you remove the error handling on the Save and rely on the catch in the overall try catch it will follow the await.
Controller:
export async function createPlayer(req,res) {
//creates a Player in the database
try {
res.status(200).send(await PlayerFunction.createPlayer(req.body));
} catch (error) {
log_error('Errored trying to create Player in controller.', error);
res.status(404).send('Error Has Occured. An Admin has been contacted.');
}
};
Middlewear
export async function createPlayer(req_body) {
//creates a Player in the database
try {
let new_Player = new Player(req_body);
await new_Player.save();
return { success: true, body: new_Player };
} catch (error) {
log_error('Errored trying to create a player.', error);
return { success: 'error', body: 'Error Has Occured. An Admin has been contacted.' };
}
};
In the async function needs to return promise-based value.
A Promise which will be resolved with the value returned by the async function, or rejected with an exception thrown from, or uncaught within, the async function.
So in your middleware createPlayer() needs to return Promise-based value.
export async function createPlayer(req_body) {
//creates a Player in the database
try {
//set new player object
let new_Player = new Player(req_body);
new_Player.save((error) => {
if (error) {
log_error('Trying to create a Player.', error)
return Promise.reject(JSON.stringify({ success: 'error', body: 'Error Has Occured. An Admin has been contacted.' }));
} else {
console.log(new_Player);
return Promise.resolve(JSON.stringify({ success: true, body: new_Player }));
};
});
} catch (error) {
log_error('Errored trying to create a player.', error);
return Promise.reject(JSON.stringify({ success: 'error', body: 'Error Has Occured. An Admin has been contacted.' }));
}
};

How does error handling work for async map inside an async function?

I have successfully created a function that creates folders according to a directory.
However, when I have tried to convert the for of into a map() method using Promise.all(), the error was not handled the same.
import { readdir, mkdir } from 'fs/promises';
const copyUsingFor = async (target) => {
try {
const dir = await readdir(`./test`, { withFileTypes: true });
for (const item of dir) {
if (item.isDirectory()) {
try {
await mkdir(`./${target}`);
}
catch (err) {
throw err;
}
}
}
}
catch (err) {
console.log(`desired err handling`);
throw err;
}
}
const copyUsingMap = async (target) => {
try {
const dir = await readdir(`./test`, { withFileTypes: true });
Promise.all(
dir.map(async item => {
if (item.isDirectory()) {
try {
await mkdir(`./${target}`);
}
catch (err) {
throw err;
}
}
})
)
}
catch (err) {
throw err;
}
}
copyUsingFor(`../`).catch(err => console.log(`An error occurred: ${err}`)) // <- Works.
copyUsingMap(`../`).catch(err => console.log(`An error occurred: ${err}`)) // <- Gives "triggerUncaughtException".
I am guessing it is because I have an async inside another, but could not figure out why it does not works the same.
Thanks!
You are missing the await in front of Promise.all, that's all. Because of this, what happens inside the Promise.all is detached from the rest of your program flow.
Side note: catch (err) { throw err } is a no-op. You can get rid of the whole try/catch if you don't do anything other than rethrowing the error in it. It feels a bit like wrapping stuff in a call to a function x => x.

Error: DPI-1002: invalid dpiConn handle: Nodejs, Oracledb

I have the following API, the API is inserting into a table based on user selection from the client. User can select different material belonging to same experiment. In my payload, I have materials as array, experiment as string. I tried several ways to resolve my error. Following was the last try:
app.post("/insertMaterials", (req, res) => {
for (let mat of req.body["material"]) {
try {
oracledb.getConnection(
{
user: "some_user",
password: "some_pw",
connectString: "someConnStr",
},
function (err, connection) {
if (err) {
console.error("1" + err);
return;
}
connection.execute(
"INSERT INTO MATERIALS (ID, MAT_NAME, EXPR) VALUES((SELECT max(ID) + 1 FROM MATERIALS), :1, :2)",
[mat, req.body["experiment"]],
(err, result) => {
if (err) {
console.error("log " + err);
}
connection.commit();
connection.close();
}
);
}
);
} catch (error) {
console.log(error);
}
}
return res.status(200).json({
title: "SUCCESS: Materials Inserted",
});
});
I always get:
triggerUncaughtException(err, true / fromPromise /);
^
[Error: DPI-1002: invalid dpiConn handle] { errorNum: 0, offset: 0 }
Before I had a separate function of the block inside the for loop and I also tried with execeuteMany. Still same error. After trying lot other ways and reading in internet, I couldn't solve the issue. Except for finally catching uncaughtException and logging the error:
process.on('uncaughtException', (error, next) => {
let date = new Date()
errorLogStream.write(`Date: ${date}. Err: ${error.stack} \n`)
return
})
By catching this exception, my program does not break anymore and data is always inserted. But it would be great to know how and when this is raised and how this can be resolved or where if I am doing a mistake.
UPDATE
Payload example: {'material': ['F99999.7', 'J84845.4'], 'experiment': 'NA32R'}
Function:
async function addMatToExpr(exp, mat) {
let connection;
try {
connection = await oracledb.getConnection(
{
user: "some_user",
password: "some_pw",
connectString: "someConnStr",
});
result = await connection.execute("INSERT INTO MATERIALS (ID,
MAT_NAME, EXPR) VALUES((SELECT max(ID) + 1 FROM MATERIALS), :1, :2)",
[exp, mat], { autoCommit: true })
} catch (error) {
return res.status(404).json({
title: error,
});
} finally {
if (connection) {
try {
await connection.close()
} catch(error) {
console.log(error)
}
}
}
}
API:
app.post("/insertMaterials", (req, res) => {
for (let mat of req.body["materials"]) {
addMatToExpr(req.body["experiment"], mat)
}
});
Added the async/await function and the api that calls the function.
You need to 'await' the Oracle function calls so each completes before continuing. Currently the connection is being closed before the statement is executed.
See all the node-oracledb documentation and examples.
E.g.
async function run() {
let connection;
try {
connection = await oracledb.getConnection(dbConfig);
result = await connection.execute(sql, binds, options);
console.dir(result, { depth: null });
} catch (err) {
console.error(err);
} finally {
if (connection) {
try {
await connection.close();
} catch (err) {
console.error(err);
}
}
}
}

Handle UnhandledPromiseRejectionWarning in a function calling another functions

I am having problems do handle UnhandledPromiseRejectionWarning in a function that call other functions making axios request.
const getCode = async () => {
const code = await baseURL.get('/gcs/login/k?codigoCanal=4')
return code
}
const posLogin = async (code) => {
const poslogin = await baseURL.get(`/resource/autenticar/${code}`)
return poslogin
}
const login = async () => {
try {
const code = await getCode();
const finishedLogin = async posLogin(code)
} catch (error) {
handleLoginError(error)
}
}
const handleLoginError = (error) => {
if (error.response.status === 400) {
throw new Error(`Bad Request; ${error.response.statusText}`)
}
if (error.response.status === 401) {
throw new Error(`Wrong credentials; ${error.response.statusText}`)
}
throw new Error('Unknown Error')
}
login()
Executing this code returns me UnhandledPromiseRejectionWarning, but I realized that if I put a try catch inside the catch of login functionn, this warning disappears
} catch (error) {
try {
handleLoginError(error)
} catch (err) {
console.log('Ooppss', err)
}
When I do this my code enter in the nested catch and the "err" value is the value of the handleLoginError(error)
How can I do the same without executing a try catch inside the catch?
It seems you need to call login as follows:
try {
await login();
}
catch(err) {
// handle here the error
}

Error: Callback was already called in loopback

I have the following code:
"use strict";
const Raven = require("raven");
Raven.config(
"test"
).install();
module.exports = function(Reservation) {
function dateValidator(err) {
if (this.startDate >= this.endDate) {
err();
}
}
function sendEmail(campground) {
return new Promise((resolve, reject) => {
Reservation.app.models.Email.send(formEmailObject(campground),
function(
err,
mail
) {
if (err) {
console.log(err);
Raven.captureException(err);
reject(err);
} else {
console.log(mail);
console.log("email sent!");
resolve(mail);
}
});
});
}
function formEmailObject(campground) {
return {
to: "loopbackintern#yopmail.com",
from: "noreply#optis.be",
subject: "Thank you for your reservation at " + campground.name,
html:
"<p>We confirm your reservation for <strong>" +
campground.name +
"</strong></p>"
};
}
Reservation.validate("startDate", dateValidator, {
message: "endDate should be after startDate"
});
Reservation.observe("after save", async function(ctx, next) {
try {
const campground = await Reservation.app.models.Campground.findById(
ctx.instance.campgroundId
);
const mail = await sendEmail(campground);
next();
} catch (e) {
Raven.captureException(e);
next(e);
}
});
};
Sorry for the poor formatting. When the flow is done I get this error:
(node:3907) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called.
I am calling the next() callback in two places, one in the try code and one in the catch code. I assume that when it all goes right, next callback is called only once, and the same when it goes wrong. But it seems that it is called twice and I don't know why.
I also tried to call next outside the try/catch code but it results in the same error. If I left only the next that is called inside the catch code it doesn't throw the error.
Any idea? Thanks!
if you are using async function you shouldn't explicitly call next, it gets automatically called.
check out this github issue for loopback async/await
so your hook can be like the following.
Reservation.observe("after save", async ctx => {
try {
const campground = await Reservation.app.models.Campground.findById(
ctx.instance.campgroundId
);
const mail = await sendEmail(campground);
} catch (e) {
Raven.captureException(e);
throw e;
}
});
NB: you don't need to wrap it in try catch unless you want to modify/work with the error.
You should declare your sendEmail method as async as it returns a promise.
async function sendEmail(campground) {
...
}
After reading this article, I created a await-handler.js file which include following code.
module.exports = (promise) =>
promise
.then(data => ({
ok: true,
data
}))
.catch(error =>
Promise.resolve({
ok: false,
error
})
);
Then in MyModel.js file, I created a async function to get a value from database as follow.
const awaitHandler = require("./../await-handler.js")
const getMaxNumber = async (MyModel) => {
let result = await awaitHandler(MyModel.find());
if (result.ok) {
if (result.data.length) {
return result.data.reduce((max, b) => Math.max(max, b.propertyName), result.data[0] && result.data[0].propertyName);
} else {
return 0;
}
} else {
return result.error;
}
}
As per #Mehari's answer, I've commented call to next() method as follow:-
module.exports = function(MyModel) {
MyModel.observe('before save', async(ctx, next) => {
const maxNumber = await getMaxNumber (MyModel);
if(ctx.instance) {
...
set the required property using ctx.instance.*
like createdAt, createdBy properties
...
// return next();
} else {
...
code for patch
...
// return next();
}
})
}
This solves the warning issue whenever saving endpoint is triggered.
But the warning issue still appear when I run the endpoint to load the resource.Like
http://localhost:3000/api/MyModel
Previously, the issue appear only when the before save operation hook gets triggered.
After encountering this issue, I checked adding access and loaded operation hooks and I found that the the warnings are issued after loaded operation hook.
MyModel.observe('access', (ctx, next) => {
return next();
})
MyModel.observe('loaded', (ctx, next) => {
return next();
})
What could have caused this issue and how can it gets resolved?

Resources