onSuccess and onError not being fired in rtk query - node.js

const [login] = useLoginMutation({
onSuccess: () => {
console.log("Success");
setAlertType("success");
setAlertMessage("Login successful!");
setOpenAlert(true);
},
onError: (error) => {
console.log("Error: " + error);
setAlertType("error");
setAlertMessage(`Login failed: ${error}`);
setOpenAlert(true);
}
});
Everything is working except that the onSuccess and onError doesn't fire. The query is successful and everything.

onSuccess and onError are not options in RTK Query.
You can not just make up options and expect them to work. Maybe you confused that with options from another library?
Generally, the hooks do not have any lifecycle callbacks. You can defined lifecycle callbacks (different ones, with different names) on endpoint level, but not on component/hook level.

const submitLoginForm = async (e) => {
e.preventDefault();
try {
const response = await login(loginData);
if(response.error) {
setAlertType("error");
setAlertMessage("Incorrect username or password");
setOpenAlert(true);
} else if (response.data) {
setAlertType("success");
setAlertMessage(response.data.message);
setOpenAlert(true);
}
dispatch(hide());
refetchLogin();
} catch (err) {
console.log(err);
}
}

Related

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);
}
}
}
}

Nodejs Promise "res.end is not a function" error

I'm refactoring my code to remove a "callback hell" using Promises, but encountered an error that I cannot pass. My code receives list of IDs and processes them making few database calls, that is why I had this "callback hell".
Everything worked fine until Promises. The res is equal 0 when I had to respond back to the client.
function processVMDelete(returnedVMIDs){
return new Promise((resolve, reject) => {
var mariasqlClient = dbConnection();
mariasqlClient.query( sqlUpdateDELETE_STATE_ByVMID, [
'DELETE',
returnedVMIDs
], function(err, rows) {
if (err){
reject(err);
}
console.log('finish update');
// dont' need to return anything here
resolve(0);
});
mariasqlClient.end();
});
}
function getListExpVM(){
return new Promise((resolve, reject) => {
var vmList = [];
var mariasqlClient = dbConnection();
mariasqlClient.query( sqlSearch_ByUSERNAMEAndSTATE, [
requesterUsername,
'ACTIVE'
], function(err, rows) {
if (err){
reject(err);
}
vmList = filterExpiredVMs(rows);
var response = {
status : 200,
success : 'Successfull',
data : vmList,
requester: requesterUsername
};
resolve(response);
});
mariasqlClient.end();
});
}
router.post('/processVMs', function(req, res) {
var returnedVMIDs = JSON.parse(req.body.data);
processVMDelete(returnedVMIDs)
.then(res => {
console.log('done');
// check if there is more available for the user:
getListExpVM()
.then(response => {
console.log('sending back list of VMs');
//===>>> ERROR HERE: res.end is not a function
res.end(JSON.stringify(response));
})
.catch(err => {
console.log('error', err.message);
logger.error("Error getting expired VMs: " + err.message);
//===>>> ERROR HERE: res.send is not a function
res.status(500).send({error: err.message})
});
})
.catch(err => {
console.log('error', err.message);
logger.error("Error processing VMs: " + err.message);
//===>>> ERROR HERE: res.send is not a function
res.status(500).send({error: err.message})
});
});
You've redefined res with this:
processVMDelete(returnedVMIDs)
.then(res => {...})
This will hide the higher scoped res associated with the overall request (the one you need to use for res.end()). Change the name of this one to something else like result and then change the corresponding references that use this result.

Render the results of two separate async.each methods

I am new to nodejs and async. Having trouble understanding how can I wrap the two separate async.each methods to have one res.render...I am trying to display a list of valid account ids, and valid user ids on the front end.
The two separate async.each methods are:
async.each(account_ids, function(accountId, callback) {
console.log('Processing accountId ' + accountId);
callingExternalApi(accountId, callback, function(err, response){
if(err){
console.log("error account");
}
console.log("account response is: ", response);
});
}, function(err) {
if( err ) {
console.log('An account failed to process');
} else {
console.log('All accounts have been processed successfully');
}
});
and
async.each(email_ids, function(emailId, callback) {
console.log('Processing email id ' + emailId);
request({
url: emailIdlookupUrl,
method: 'POST',
json: {
email_address: emailId
}
}, function (err, response, body) {
if (err) {
logger.error(err);
req.flash('error', err.message);
return res.redirect('?');
}
if (response.statusCode !== 200) {
const msg = 'Unable to verify user';
req.flash('error', msg);
return res.redirect('?');
}
console.log("user id is: ", body.user.id);
callback();
});
}, function(err) {
if( err ) {
console.log('An email failed to process');
} else {
console.log('All user emails have been processed successfully');
}
});
Any help is highly appreciated. Please excuse me for any redundant callbacks or error logging. Still learning nodejs.
Thanks!!
The main issue is not that you are invoking both of these async.each calls. The problem is that they will run in parallel, and the fastest one to invoke req.* functions or callback function will return a response to the connection.
Both of these functions return promises if their callback parameters are omitted.
I recommend reading up on both the async library and JS async/await in general:
https://javascript.info/async-await
https://caolan.github.io/async/v3/docs.html#each
https://zellwk.com/blog/async-await-express/
Note that async also accepts native async functions, which many finder cleaner and easier to understand.
Here is what I think you want from the code above, including compiling the results into lists:
var request = require("request-promise");
async function checkAccounts(account_ids) {
const valid_accounts = [];
await async.each(account_ids, async function(accountId) {
console.log("Processing accountId " + accountId);
const extAPIresult = await callingExternalApi(accountId);
console.log("account response is: ", extAPIresult);
});
valid_accounts.push(extAPIresult);
console.log("All accounts have been processed successfully");
return valid_accounts;
}
async function checkEmails(email_ids) {
const valid_emails = [];
await async.each(email_ids, async function(emailId) {
console.log("Processing email id " + emailId);
const reqresult = await request({
url: emailIdlookupUrl,
method: "POST",
json: {
email_address: emailId
}
});
if (reqresult.statusCode !== 200) {
throw new Error("Unable to verify user");
}
valid_emails.push(reqresult.body.user.id);
console.log("user id is: ", reqresult.body.user.id);
});
console.log("All emails have been processed successfully");
return valid_emails;
}
async function doChecks() {
const accounts = checkAccounts(account_ids);
const emails = checkEmails(email_ids);
const responses = await Promises.all([accounts, emails]);
console.log("All checks have been processed successfully");
return responses;
}
function get(req, res) {
doChecks()
.then(responses => {
res.send("All checks have been processed successfully");
res.send(String(responses));
})
.catch(err => {
req.flash("error", err.message);
res.redirect("?");
});
}

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?

Server sends success even if didn't find anything

I send data from my input fields to my api:
$.ajax({
url: '/api/login',
type: 'GET',
dataType: 'json',
ContentType: 'application/json',
data: {formData},
success: (data) => {
console.log('SUCCESS')
console.log(data)
this.setState({
isInProcess: false
})
},
error: (jqXHR) => {
console.log(jqXHR)
console.log('ERROR')
this.setState({isInProcess: false})
}
})
on my server-side I have a function to see if I have required user in db:
async function findUser(data) {
try {
const user = await User.findOne({email: data.email,
password: data.password})
console.log('User was found')
return { user }
} catch (err) {
console.log('error', err)
throw err
}
}
which will be executed here:
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
return res.json(foundUserData)
} catch (err) {
return res.status(400).json(err)
}
})
It works fine, but if a user wasn't found in db i sends success anyway. Why?
await findUser(data.formData) won't throw error, return either null or user object. You may check something following
app.get('/api/login', async (req, res) => {
const data = req.query
try {
const foundUserData = await findUser(data.formData)
if(foundUserData && foundUserData.user) {
return res.json(foundUserData)
} else {
return res.status(400).json({message: 'User not found'});
}
} catch (err) {
return res.status(500).json(err)
}
})
It sends success because none of your queries error'ed, just because it didn't find anything does not mean that the query failed because it obviously succeeded in finding out if what ever you're looking for exists or not.
To send an error in case of not found you need to check if response is empty in which case you want to send error
When no user is find you get a null value. You may try to put more logic on your success parameter with that for example:
success: function (data) {
if(!!data && data != null) {
alert('Success');
} else {
alert('No data');
}
}

Resources