Catching exception errors when logging in via NodeJS + MySQL - mysql

Recently I've been trying to learn NodeJS to set up a log in process, so I decided to write all the errors and make exceptions for them. My question is how can I make sure each if is responsible for each error code. I haven't worked with try and catch before so this is a new territory for me.
Also is it better to use multiple try-catch or should I consider using 1 block where I can use a switch for example (used else if here as a quick example).
Table with Status errors
0 - no connection with database.
1 - connection ok but we dont have any privileges for access to the
database or something like that.
2 - all ok.
3 - ok, but no data found in query results.
4 - error getting results of query.
5 - other.
module.exports = (username,password,connection ) => {
var data ={
"Status" : null,
"Data" : {} //JSON results inside of Data Json
}
try{
connection.query("SELECT id FROM players", function (error, results, fields) {
if (error){
data.Status = 0;
data.Data= "No connection can be established with the database";
return data
}
else if(error){
data.Status = 1;
data.Data= results + "Connection OK but no priviliges";
return data
}
else if(error){
data.Status = 2;
data.Data=results + "connection running";
return data
}
else if(error){
data.Status = 3;
data.Data=results + "No data found in query results";
return data
}
else if(error){
data.Status = 4;
data.Data=results;
return data
}
else if(error){
data.Status = 5;
data.Data=results;
return data
}
});
}
catch(e){
console.log(e);
data.Status= 2;
data.Data=null;
return data;
}
};

Welcome to async programming, your try/catch block won't do anything for any I/O process, all errors are handled by error object in the callback function. (unless you use the last async/await ES6 pattern)
connection.query("SELECT id FROM players", function (error, results, fields) {
if (!error) { // no error, return results
data.status = 2;
data.Data = results;
return data;
}
// for all error code, please check mysql library document
// https://www.npmjs.com/package/mysql#error-handling
if (error.code === 'ER_ACCESS_DENIED_ERROR') {
data.Status = 1;
data.Data=results;
return data
}
// handle any other error codes
// if ....
});
Edit: please note that, your exported function in module.exports won't return anything because you are calling database query which is an async I/O process and requires another callback function to get the data returned by database

This will never work as expected :
if (error){
console.log("I'm the error");
return;
} else if(error){
console.log("I will never be display on error because of return in the first if");
}
Should be :
if (!error){
// No error
} else if(error === 'something'){
// Error something
} else if ....
// Other type of error
} else {
// Unknown error
}
You can use a switch instead in a more elegant way :
const data = { Status: 1, Data: results }
if(error) {
switch(error.code) {
case 'ER_ACCESS_DENIED_ERROR' :
data.Satus = 2;
return data;
...
}
}
return data;

Related

Express JS query Error Handling not working

this is my first post on Stackoverflow, so please be kind.
I have a huge problem, which I couldn't fix by googling (which is pretty rare).
I want to create a simple error handling in my query, but it won't work.
Here's the code:
pool.query("SELECT password_hash FROM User WHERE email = ?",
req.body.EMailLogin, (error, results, fields) => {
if(error) {
// It executes the if aswell as the else statement and I dont know why (if(error) seems to be ignored even if its true)
} else {
// And then it crashes here, because password_hash is undefined
let hash = results[0].password_hash;
bcrypt.compare(req.body.PasswordLogin, hash, function(err, result) {
if (result == true) {
ses.user = req.body.EMailLogin;
req.session.cookie.expires = false;
req.session.save(() => {
return res.redirect('/index');
});
} else {
res.render(); // My Page for Wrong Password (ignore this)
}
});
}
}
);
Throw the error inside the if
if(error) {
throw error;
} else {
I think that the error is how you're passing the parameter, it should be an array:
pool.query("SELECT password_hash FROM User WHERE email = ?",
[req.body.EMailLogin],
I hope this fixes your problem.
You missed to check weather query return data or not and also you can pass values either using object or array(in your case, should be array)
pool.query("SELECT password_hash FROM User WHERE email = ?", [req.body.EMailLogin],
(error, results, fields) => {
if (error) {
// any error like wrong query, connection closed, etc.
// It executes the if aswell as the else statement and I dont know why (if(error) seems to be ignored even if its true)
} else if (results.length === 0) {
// email not found in database
// My Page for Wrong Email ???
} else {
// And then it crashes here, because password_hash is undefined
let hash = results[0].password_hash;
bcrypt.compare(req.body.PasswordLogin, hash, function (err, result) {
if (result == true) {
ses.user = req.body.EMailLogin;
req.session.cookie.expires = false;
req.session.save(() => {
return res.redirect('/index');
});
} else {
res.render(); // My Page for Wrong Password (ignore this)
}
});
}
}
);

NodeJs MySql multiple update

I have a method in NodeJs using Express framework, in which I am iterating an array and making an update in a Mysql DB,
The Code receives a Connection object and a Post Body,
The Post Request Body is an Array of objects, of the data to be saved in the DB,
I am trying to loop the objects one by one and save them in the DB using an Update Query.
Now the strange part is, the code works only if it gets called twice immediately,
Ie. On testing I found out, I have to make the API request twice in order for the code to save the data.
I get the following error on the first API call -
Error Code: 1205. Lock wait timeout exceeded; try restarting transaction
It's a simple Update call, I checked the MySql processes and there was no deadlock,
SHOW FULL PROCESSLIST;
But the same code work's on the immediate 2nd API call.
let updateByDonationId = async (conn, requestBody, callback) => {
let donations = [];
donations = requestBody.donations;
//for(let i in donations){
async.each(donations, function(singleDonation, callback) {
//let params = donations[i];
let params = singleDonation;
let sqlData = []
let columns = "";
if(params.current_location != null){
sqlData.push(params.current_location);
columns += "`current_location` = ?,";
}
if(params.destination_location != null){
sqlData.push(params.destination_location);
columns += "`destination_location` = ?,";
}
if(columns != ''){
columns = columns.substring(0,columns.length-1);
let sqlQuery = 'UPDATE donation_data SET '+columns
+' WHERE donation_id = "' + params.donation_id + '"';
conn.query(sqlQuery, sqlData, function (err, result) {
logger.info(METHOD_TAG, this.sql);
if (err) {
logger.error(METHOD_TAG, err);
return callback(err, false);
}
})
}
else{
return callback(null, false);
}
columns = "";
sqlData = [];
},
function(err, results) {
if (err) {
logger.error(METHOD_TAG, err);
return callback(err, false);
}
else{
return callback(null, true);
}
});
//return callback(null, true);
} // END
Also referring the following, i guess he was getting an ER_LOCK_WAIT_TIMEOUT for weird reason as well -
NodeJS + mysql: using connection pool leads to deadlock tables
The issue seems to be with the Non blocking Async nature of Node as rightly pointed out
Can anyone help with a correct code?
I'd say the asynchronous nature of Node.js is going to be causing you issues here. You can try rewriting your loop. You can either use promises or the async.eachSeries method.
Try changing your loop to use the below:
async.eachSeries(donations, function(singleDonation, callback) {
.query() the method is asynchronous, because of this your code tries to execute one query after another without waiting for the former to finish. On the database side, they just get queued up if they happen to affect the same portion of it, i.e., one query has a "Lock" on that portion of the database. Now one of the transactions has to wait for another to finish and if the wait is longer than the threshold value then the error which you are getting is caused.
But you said that you are not getting the error on the second immediate call, my guess is that during first call(s) the data was cached so therefore the second call was faster and it was fast enough to keep the wait under threshold value thus the error was not caused on the second call.
To avoid this all together and still maintain the asynchronous nature of code you can use Promise along with async-await.
The first step is to create a Promise based wrapper function for our .query() function, like so:
let qPromise = async (conn, q, qData) => new Promise((resolve, reject) => {
conn.query(q, qData, function (err, result) {
if (err) {
reject(err);
return;
}
resolve(result);
});
});
Now here is your modified function which uses this Promise based function and async-await:
let updateByDonationId = async (conn, requestBody, callback) => {
let donations = [];
donations = requestBody.donations;
try {
for (let i in donations) {
let params = donations[i];
let sqlData = [];
let columns = "";
if (params.current_location != null) {
sqlData.push(params.current_location);
columns += "`current_location` = ?,";
}
if (params.destination_location != null) {
sqlData.push(params.destination_location);
columns += "`destination_location` = ?,";
}
if (columns != '') {
columns = columns.substring(0, columns.length - 1);
let sqlQuery = 'UPDATE donation_data SET ' + columns
+ ' WHERE donation_id = "' + params.donation_id + '"';
let result = await qPromise(conn, sqlQuery, sqlData);
logger.info(METHOD_TAG, result); // logging result, you might wanna modify this
}
else {
return callback(null, false);
}
columns = "";
sqlData = [];
}
} catch (e) {
logger.error(METHOD_TAG, e);
return callback(err, false);
}
return callback(null, true);
}
I wrote the code on fly so there maybe some syntactical error(s).

HapiJS - MySQL: Query successful but postman returns Internal server error

I am trying to create an authentication system using Hapi and MySQL, I am testing it using postman, and I am also logging the output of the query on the terminal console.
The thing is, the console outputs the query successfully, however, postman returns An internal server error occurred, and the console doesn't return any error. I'll send the handler function of my route, found below:
handler: async function(req, h) {
const pass = req.payload.password;
const username = req.payload.username;
var res;
res = await con.query("SELECT * FROM `Person` WHERE `Username` = ?", username,
(err, rows, fields) => {
if(err) {
console.log("Query Error: ", err, "!");
return err;
} else {
console.log("Query Successful!");
const person = JSON.parse(JSON.stringify(rows[0]));
console.log(person);
if(person != null) {
//const hashedPass = crypto.pbkdf2Sync(req.payload.password, person.salt, 10000, 64, 'sha1').toString('base64');
if(pass != person.Password) {
return boom.badRequest('Invalid username/password.');
} else {
var token = jwt.sign(person, config.jwtKey);
person.token = token;
return person;
}
} else {
return boom.badRequest('Invalid username/password. Failed.');
}
}
}
);
return res;
}
I solved the problem by adding another node_module that encapsulates the regular mysql node module functions with promises.
The package is called promise-mysql.

NodeJS async MySQL call to connection pool returns no result

I'm currently working with chatbots and trying to work out the new await / async structure in NodeJs.
My code currently looks like this:
exports.checkUser = async function (userId, callback){
let result;
try{
result = await pool.query('SELECT * FROM users WHERE id = ?;',
[userId]);
if(!result || result.length == 0)
{
return false;
}
else if(result.length != 0)
{
return true;
}
}
catch(err)
{
console.log(err);
callback(err, null);
}
};
I went under the assumption I don't have to fiddle with promises while using asyc/await structure.
I am calling this function somewhere else like this:
mysql.checkUser(user).then((result) =>
{
//console for debug
console.log(result);
});
Well, I know the checks for the success are pretty plain, I don't seem to get a decent result.
It's always throwing me something like inside the result object:
_callSite: Error
at Pool.query (/app/node_modules/mysql/lib/Pool.js:199:23)
at Object.exports.checkUser (/app/lib/mysql/mysql.js:49:29)
at Object.exports.checkUser (/app/lib/auth/authentication_engine.js:28:11) [...]
pool.query is not returning a Promise, so the execution will fail when it is called as an async function.
It is indeed a good idea to use mysql2 package, more on: https://www.npmjs.com/package/mysql2#using-promise-wrapper

can't set headers after they are sent return res.json

exports.saveUserInterfaceConfig = function(req,res){
var body = req.body;
console.log('body:['+JSON.stringify(body)+']');
var mysql = require('mysql');
var UiConfigId = [];
var connection = getDBConnection();
if(body && connection){
connection.beginTransaction(function(err){
if (err) {
/*var errorObj = {error:{code:0, text:'backend error'}};
return res.json(200, errorObj);*/
throw err;
}
var companyId = body.companyId;
var moduleId = body.moduleId;
var submoduleId = body.submoduleId;
var formfieldsId = body.formfieldsId;
for(var index3 in formfieldsId){
var UIConfigInfo = {Company_CompanyId: companyId, Modules_ModuleId: moduleId, SubModule_SubModuleId: submoduleId, SubmoduleFieldConfig_SubmoduleFieldConfigId: formfieldsId[index3]};
var saveUIConfigQuery = 'INSERT INTO ui_config SET ?';
connection.query(saveUIConfigQuery, UIConfigInfo, function(err, result) {
if (err) {
return connection.rollback(function() {
throw err;
});
}
UiConfigId.push(result.insertId);
console.log('result:['+JSON.stringify(result)+']');
connection.commit(function(err) {
if (err) {
return connection.rollback(function() {
connection.end(function(err) {
// The connection is terminated now
});
throw err;
});
} else {
connection.end(function(err) {
// The connection is terminated now
});
}
return res.json(200,{UiConfigId: UiConfigId});
console.log('UiConfigId:['+JSON.stringify(UiConfigId)+']');
console.log('success!');
// connection.release();
});
})
}
})
}
}
I have the above in my Node API. I have to execute same query in loop more than once . but im facing an issue placing the return statement for which im getting the below error.
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
How do I fix it?
you are calling res.json multiple times in a loop, that is the reason you are getting that error..
In Simple Words., This type of error will get when you pass statements or something after sending response.
for example:
res.send("something response");
console.log("jhgfjhgsdhgfsdf");
console.log("sdgsdfhdgfdhgsdf");
res.send("sopmething response");
it generates, what the error u got.!! Beccoz once the response have been sent, the following res.send Will not be executed..because, we can send response only once per a request.!!
for this you need to use the callbacks.
Good Luck
The reason you are getting that error is because you are calling res.json multiple times in a loop.
First of all, you should be using a callback mechanism to execute the query in a loop. For'ing over it can mess up by executing multiple queries before even the others are finished.
And coming to the response, it also should be done through a callback based on a condition. Condition can be to check whether you have finished all the queries successfully.
Here is a page with good info on exactly what you need:
https://mostafa-samir.github.io/async-iterative-patterns-pt1/