I want to get this functionality if(thereIsSomeError) //stop executing further. for example if there some error accurs in middleware or in the callback then i don't want to execute callback(in the app.route) and the middleware further
I tried this code. But i'm still getting req.err as true. how can i fix this issue
// My MiddleWare
export let Middleware=()=> {
return (req,res,next)=>{
next()
console.log(req.err) // Problem is here.. i'm still getting req.err(true)
if(!req.err){
db.query(`query`,(error, responseData)=>{
if(error) console.log(error)
db.query(`second query`,{...// send data to the
database})
})
}
}
}
//End point
app.post('/addStudent',Middleware, (req, res) => {
//setting error to true initially
req.err=true;
let data = req.body
db.query(`query `, data.username, (err, d) => {
if (err) return res.json(err)
else {
// since no Error accured so set the error to false
req.err=false;
let q = 'query';
let values = {//data here}
db.query(q, values, (err, data) => {
if (err) return res.status(200).json(err)
else return res.status(200).json({ data })
})
}
})
})
First, a middleware runs BEFORE a request, NOT AFTER. If you set req.err = true in your POST endpoint, IT WILL STAY TRUE, meaning your database call will certainly return an error.
Second, to successfully abort a middleware call, use return. Returning a function stops it immediately. You can choose either to return next(err) to forward the error to the handler, or to use return res.send('Error') to terminate the response in the middleware.
Related
I am getting an error trying to call an existing smart contract function using call().
The error is "Returned values aren't valid, did it run Out of Gas? You might also see this error if you are not using the correct ABI for the contract you are retrieving data from, requesting data from a block number that does not exist, or querying a node which is not fully synced." My code is below
let url = 'https://api.etherscan.io/api?module=contract&action=getabi&address=0x672C1f1C978b8FD1E9AE18e25D0E55176824989c&apikey=<api-key>';
request(url, (err, res, body) => {
if (err) {
console.log(err);
}
let data = JSON.parse(body);
let contract_abi = JSON.parse(data.result);
let contract_address = '0x672C1f1C978b8FD1E9AE18e25D0E55176824989c';
const contract = new web3.eth.Contract(contract_abi, contract_address);
contract.methods.totalSupply().call()
.then(result => {
console.log('result', result);
}).catch(err => {
console.log('error: ', err);
})
})
When I execute the same function using send() it works, however I need the return value of the function which is why I want to use call(). I am using ganache to set up a local test network which is working fine. Thanks!
I have some raw json that I'm trying to send to my back end server in mysql. I'm currently trying to loop through the specific array in the json that I need and sending data from each of the children in the array via a POST request but I am getting "Cannot set headers after they are sent to the client".
app.post('/reddit-import', function (req, res) {
console.log("Route /reddit-import POST");
let data = req.body.data.children
data.forEach(child => {
let sql1 = `CALL insert_user('${child.data.author}',
'${child.data.author_fullname}');`
connection.query(sql1,
data,
function (errQuery, result) {
if (errQuery) {
console.log(errQuery);
res.json({status: "Error", err: errQuery});
res.end();
} else {
console.log("Insert ID: ", result.insertId);
res.json({status: result.insertId, err: ""});
res.end();
}
}
);
When I send the POST request, my backend gets 2 rows of data before it hits me with the error message...any ideas?
You seem to be ending your outer response in the data.forEach with a res.end(), which I’m assuming is used to indicate the end of the outer HTTP request to the client. Did you perhaps mean to use “result” there instead?
Try this if you need to keep track insert IDs:
app.post('/reddit-import', function(req, res) {
console.log("Route /reddit-import POST");
let data = req.body.data.children
const insertIds = data.map(child => {
return new Promise((resolve, reject) => {
const sql = `CALL insert_user('${child.data.author}', '${child.data.author_fullname}')`;
connection.query(sql, (err, result) => {
if (err) {
console.log(err);
return reject(err);
}
console.log("Insert ID: ", result.insertId);
return resolve(result.insertId);
});
});
});
return Promise.all(insertIds)
.then(ids => {
return res.json({
insertIds: ids
});
})
.catch(err => {
return res.status(500).json({
message: 'got query error'
});
});
});
What this basically does is that on each query, you keep track of the insert IDs. We need to use Promises because the query() function is asynchronous, meaning it runs independently and there's no other way to keep track of the data outside of its function(err, result) callback. Now we have an array of Promises which contains the insert IDs, and what's left is to send a response that this is successful. And in order to do that, we can't simply do res.json(insertIds) because insertIds is an array of Promises and we still need to extract the values. We can easily extract all data at once from an array of Promises by using Promise.all(insertIds).then(ids => ...). If you wish to send a response informing that the request is successful, do so in this then callback. Lastly and most importantly, we handle errors in a Promise chain's .catch() block. This is where you want to send a response informing the client that there are errors.
Some things that we can improve from this solution is to implement rollbacks in case we have errors, and of course validations of parameters. Unfortunately I have to leave this to the OP to implement.
Also, keep in mind you should only send a response once and only once each request.
I have programme in nodejs & mysql like below
db.query()
.then(1)
.then(2)
.then(3)
.catch()
I am checking a value from database in then(1) and trying to return response from there.In then(2) , I am executing another code that uses some data from result of then(1) and so on..
My problem: When returning response from then(1), catch() is calling(because then(2) have error, not getting data from then(1)) . So is there any way I can stop further execution in then(1) so that then(2) and catch() couldn't call ?
db.query('query......', [val1, val2])
.then(rslt => { return res.json({ mssg: "Email already exists!", error: "Email already exists!" }) })
.then(user => { return db.query('INSERT INTO ', value, (err, res, flds) => { err ? reject(err) : resolve(res) }) })
.then(user => { return res.json({ mssg: "Success", success: true}) })
.catch( (err) => { console.log(err) })
You can (and should) use an async function, instead of using the lower-level .then() API of the Promise object:
async function doTheThing() {
try {
const result = await db.query('...');
if (result) { // user exists
return res.json({...}); // this will end the entire function
}
const user = await db.query('...');
return res.json({...}); // success
} catch (err) {
console.log(err); // I don't recommend doing this. try/catch should be for recovery
}
}
I'm using node.js and express, also mysql.
I use a connection pool to request connections and create a promise on it, to limit callback nightmare, the following snippet is set in a file that I import later, note that that I set an handler on error to not terminate the application in case of anything going really wrong
exports.getConnection = () => {
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) {
reject(`Could not obtain the connection from the pool: ${err}`);
}
connection.on('error', err => {
console.log(`SQL error (code: ${err.code}, message: ${err.sqlMessage}) while executing query: ${err.sql}`);
});
resolve(connection);
});
});
};
And here is an example of usecase (the idea is to get the connection, chain the query in the then, and if a non fatal error happen I will throw it and handle the connection release in the catch handler
// Exception handler that release the connection then call the callback
function releaseConnectionHandler(err, connection, callback) {
connection.release();
callback(err, null);
}
exports.someRequest = function(ID, callback) {
sqlPool.getConnection().then(connection => {
connection.query("SELECT * from tableNotExists",
(err, result) => {
if (err) {
throw ({ err, connection, callback });
}
connection.release();
callback(null, result);
});
}).catch(({ err, connection, callback}) => releaseConnectionHandler(err, connection, callback));
};
The query will fail, but I see that the handler is not even called (I put some trace in it...) and the application terminates on
node_modules/mysql/lib/protocol/Parser.js:80
throw err; // Rethrow non-MySQL errors
Correct querie yoeld no troubles...Any ideas what I did wrong on the error handling ?
You're re-throwing the error passed to the callback of your query, which the library you're using then re-throws as well, and finally isn't properly caught and handled anywhere and results in a failure. You're not in the context of the Promise when you throw, but the context of the callback function called from the mysql module.
You're also unnecessarily mixing promises and callbacks, in particular the function you're exporting. Your question indicates that you want to move away from callbacks, so I'm going to base this answer on that indication.
To solve the main issue, don't throw the error. Instead, pass it up to the callee:
const promisify = require("util").promisify;
exports.someRequest = function (ID) {
return sqlPool.getConnection().then(connection => {
return promisify(connection.query)("select * from tableNotExist")
.finally(connection.release);
});
};
The connection will always be released back to the pool, whether successful or on error. You can then call the method with:
yourModule.someRequest(id).then((results) => {
// Do something with the result set
}).catch((e) => {
// Handle error. Can be either a pool connection error or a query error.
});
If you have the possibility to use async/await, the code can be rewritten:
const promisify = require("util").promisify;
exports.someRequest = async function (ID) {
let connection = await sqlPool.getConnection();
try {
return await promisify(connection.query)("select * from tableNotExist");
} finally {
connection.release();
}
};
I also recommend using node-mysql2 since they have a Promise-based API in addition to their callback-style API and in my experience better performance as well. Then you don't have to write these tedious wrappers and instead just require('mysql2/promise') and be good to go.
I am wondering what the proper way is to make a server response in a NodeJS Express app when an internal server error occurs. Here is some simplified code for registering users. The main issue being, if an internal server error happens, I want to log the error, but also respond to the client with a different message. What I have below is what my current solution is, but I feel like I'm not doing it properly (or not following the conventional way). I currently have an async waterfall setup which is called from the route.
//Controller.js
function verifyInputs(user, resCallback, callback) {
//verify user inputs (ie. passwords match)
if (valid) {
callback(null)
} else {
resCallback('whatever was wrong with inputs', 409)
callback('ok')
}
}
function checkIfUserExists(user, resCallback, callback) {
db.getPool().getConnection((err, connection) => {
if (err) {
resCallback('custom response error message', 500)
callback(err)
return
}
var sql = 'SELECT...'
connection.query(sql, (err, results) => {
connection.release()
if (err) {
resCallback('another custom response error', 500)
callback(err)
return
}
if (results.length > 0) {
resCallback('user already exists')
callback('ok')
}
})
)
}
module.exports.registerNewUser(user, callback) {
async.waterfall([
async.apply(user, callback, verifyInputs),
async.apply(user, callback, checkIfUserExists)
],
function(err, reults) {
if (err === 'ok') return
//log error or whatever here
})
}
This register function is called from the routes function:
//Router.js
router.post('/register', (req, res, next) => {
var newUser = //get user data from req
controller.registerNewUser(newUser, (msg, statusCode) => {
res.statusCode(statusCode)
res.send(msg)
})
})
The code above shows how I log the error while responding to the client with a different message. Is this the right or an OK way to do this?
Or maybe I shouldn't use a waterfall at all for this, and do something like this which would give me access to the res object at all stages without multiple callbacks:
router.post('/register', verifyInputs(), checkIfUserExists(), (req, res, next) => {
var newUser = //get user data from req
controller.registerNewUser(newUser, (msg, statusCode) => {
res.statusCode(statusCode)
res.send(msg)
})
})
I'm relatively new to server back end programming, and I am new to NodeJS and Express. I just want to make sure what I am doing the proper.