I would like to know how to send error code in promise as response in nodejs. Error in Promise Not sending any error in response object in NodeJS/Express
module.exports.providerData = function (reqUrl, query) {
return new Promise(async function (resolve, reject) {
try {
var validUrl = checkValidParamters(reqUrl, query);
if(validUrl != true){
throw new Error('failed');
}
else{
sendcountry = countryjson.filter(function (send) {
return send.country_name == param_sendcountry;
})
var provider_sendcncode = sendcountry[0].country_code;
var receive = countryjson.filter(function (pr) {
return pr.country_name == param_receivecountry;
})
var valid = true;
var valid_obj = { validstatus: valid};
resolve(valid_obj);
}
}
catch (err) {
reject(err);
}
});
}
in app.js
router.get('/', function (req, res, next) {
if (getcountries == null && getcurrencies == null && getproviders == null) {
util.providerData(req.originalUrl, req.query).then(obj => {
res.render("corridor.ejs");
}).catch(err=>{
res.status(401).send({ error : err.message });
})
}
else {
console.log('just return');
util.providerData(req.originalUrl, req.query).then(obj => {
res.render("corridor.ejs");
}).catch(err=>{
res.status(401).send({ error : err.message });
})
}
});
I need to catch the error response res.status(401).send({ error : err.message }); if export function is returning false/error
your promise doesn't resolve anything. to resolve, you just simple return your response.
router.get('/', function (req, res, next) {
if (getcountries == null && getcurrencies == null && getproviders == null) {
return util.providerData(req.originalUrl, req.query).then(obj => {
return res.render("corridor.ejs");
}).catch(err=>{
return res.status(401).send({ error : err.message });
})
}
else {
console.log('just return');
return util.providerData(req.originalUrl, req.query).then(obj => {
return res.render("corridor.ejs");
}).catch(err=>{
return res.status(401).send({ error : err.message });
})
}
});
Related
I am writing mysql query with transaction but its not waiting to be completed and returns the result even before the function has executed.
Can someone please help me to know how to make function to wait for response?
The calling function is something like this:
deductUserPoint = await helper.deductUserPoint2(data)
console.log('===============================================')
console.log(deductUserPoint)
if (deductUserPoint.isError === true) {
let error = {}
error.isError = true
error.message = 'Unable to deduct amount'
error.error = deductUserPoint.error
res.status(200).json(error)
} else {
res.status(200).json({ 'isError': false, 'message': 'success' })
}
I always get deductUserPoint as undefined because it does not wait for deductUserPoint2 to return response
The deductUserPoint2 is as follows:
async deductUserPoint2(params) {
try {
this.db.connection.getConnection(function(err, conn) {
console.log('1111111111')
conn.beginTransaction(function(err) {
if (err) {
throw err
}
console.log(params)
console.log('2222222222')
conn.query('SELECT id, `expert_id`, user_id, status FROM `call` WHERE `id` = ?', [params.callId], function (error, callInfo, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('33333333')
let callLength = null
if (params.callMinute === 'entire_day') {
callLength = 'entire_day'
} else {
const callMinutes = Math.round(params.callMinute)
if (callMinutes <= 30) {
callLength = '30_min'
} else if (callMinutes >= 31 && callMinutes <= 60) {
callLength = '60_min'
} else if (callMinutes >= 61 && callMinutes <= 90) {
callLength = '90_min'
} else if (callMinutes >= 91) {
callLength = '120_min'
}
}
console.log('4444444444')
conn.query('SELECT `amount` FROM `expert_charges` WHERE `status` = "active" AND `call_length` = ? AND `expert_id` = ?', [callLength, callInfo[0].expert_id], function (error, points, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('555555555555')
let data = {
fromUserId: callInfo[0].user_id,
fromUserType: 'user',
to_user_id: 0,
to_user_type: null,
category: 'call',
type: 'debited',
callId: params.callId,
amount: points[0].amount,
note: params.note,
point: points[0].amount,
current_balance_point: 0
}
let input = Object.values(data)
conn.query('INSERT INTO wallet (`from_user_id`, `from_user_type`, `to_user_id`, `to_user_type`, `category`, `type`, `call_id`, `amount`, `note`, `point`, `current_balance_point`) VALUES ?', [[input]], function (error, wallet, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('666666666666')
conn.query('UPDATE user SET total_points = total_points - ? WHERE id = ?', [points[0].amount, callInfo[0].user_id], function (error, updateUserPoint, fields) {
if (error) {
return conn.rollback(function() {
throw error
})
}
console.log('7777777777')
conn.commit(function(err) {
if (err) {
return conn.rollback(function() {
throw err
})
}
console.log('888888888')
return {
"isError": false,
"status": "success"
}
})
})
})
})
})
})
})
} catch (error) {
console.log(error)
return {
"isError": true,
"error": error.toString()
}
}
Error it prints is :
undefined
(node:4197) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'isError' of undefined
at router.post (/Users/msmexmac/node/msmex-backend/msmex-api/api/wallet.js:120:23)
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:4197) 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:4197) [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.
1111111111
{ callId: 5, note: 'Deduction for call', callMinute: 25 }
2222222222
33333333
4444444444
555555555555
666666666666
7777777777
888888888
You can't use async functions like that, you have to return a promise to be able to wait for your callbacks. Your function would have to end up like this:
function deductUserPoint2(params) {
return new Promise(function (resolve, reject) {
try {
this.db.connection.getConnection(function (err, conn) {
console.log('1111111111')
conn.beginTransaction(function (err) {
if (err) {
return reject(err)
}
console.log(params)
console.log('2222222222')
conn.query('SELECT id, `expert_id`, user_id, status FROM `call` WHERE `id` = ?', [params.callId], function (error, callInfo, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('33333333')
let callLength = null
if (params.callMinute === 'entire_day') {
callLength = 'entire_day'
} else {
const callMinutes = Math.round(params.callMinute)
if (callMinutes <= 30) {
callLength = '30_min'
} else if (callMinutes >= 31 && callMinutes <= 60) {
callLength = '60_min'
} else if (callMinutes >= 61 && callMinutes <= 90) {
callLength = '90_min'
} else if (callMinutes >= 91) {
callLength = '120_min'
}
}
console.log('4444444444')
conn.query('SELECT `amount` FROM `expert_charges` WHERE `status` = "active" AND `call_length` = ? AND `expert_id` = ?', [callLength, callInfo[0].expert_id], function (error, points, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('555555555555')
let data = {
fromUserId: callInfo[0].user_id,
fromUserType: 'user',
to_user_id: 0,
to_user_type: null,
category: 'call',
type: 'debited',
callId: params.callId,
amount: points[0].amount,
note: params.note,
point: points[0].amount,
current_balance_point: 0
}
let input = Object.values(data)
conn.query('INSERT INTO wallet (`from_user_id`, `from_user_type`, `to_user_id`, `to_user_type`, `category`, `type`, `call_id`, `amount`, `note`, `point`, `current_balance_point`) VALUES ?', [[input]], function (error, wallet, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('666666666666')
conn.query('UPDATE user SET total_points = total_points - ? WHERE id = ?', [points[0].amount, callInfo[0].user_id], function (error, updateUserPoint, fields) {
if (error) {
return conn.rollback(function () {
return reject(error)
})
}
console.log('7777777777')
conn.commit(function (err) {
if (err) {
return conn.rollback(function () {
return reject(err)
})
}
console.log('888888888')
return resolve({
"isError": false,
"status": "success"
})
})
})
})
})
})
})
})
} catch (error) {
console.log(error)
return resolve({
"isError": true,
"error": error.toString()
})
}
})
}
Then you use reject(err) instead of throw err and resolve(value) instead of return value.
Another approach is using utils.promisify as #georg suggested.
When I get to the end of the code below, it always returns "undefined" and I don't know why!
function UserLogged (session) {
if (session === null) {
var err = new Error('Not logged in');
err.status = 400;
return {user : null, err : err};
}
User.findById(session.userId)
.exec(function (error, user) {
if (error) {
return {user : null, err : error};
}
else {
if (user === null) {
var err = new Error('Not authorized!');
err.status = 400;
return {user : null, err : err};
}
else {
console.log("User found and ok!");
return {user : user, err : null};
}
}
});
}
It does log "User found and ok!" on the console, but still returns "undefined"
UserLogged is Asynchronous function so one way to handle is to add a callback:
function UserLogged (session, next) {
if (session === null) {
var err = new Error('Not logged in');
err.status = 400;
return next({user : null, err : err});
}
User.findById(session.userId)
.exec(function (error, user) {
if (error) {
return next({user : null, err : error});
}
else {
if (user === null) {
var err = new Error('Not authorized!');
err.status = 400;
return next({user : null, err : err});
}
else {
console.log("User found and ok!");
return next({user : user, err : null});
}
}
});
}
and then you call UserLogged like this:
something.UserLogged(sessionData, function(result) {
console.log(result)
})
I would like to make a if else return (for conrtole) but: "UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
"
exports.delete = function (req, res) {
Parking.findById(req.params.id).exec()
.then(function (parking) {
if (userController.ensureAuthorized(req, 'Director', parking.id)) {
return parking;
}
return res.status(403).send({msg: 'unauthorized'});
})
.then(function (parking) {
User.update().exec();
return parking;
})
.then(function (parking) {
return Parking.remove({_id: parking._id}).exec();
})
.then(function () {
res.status(200).json({msg: 'Ok ! Parkink remove'});
})
.catch(function (err) {
return res.status(400).send(err);
});
};
Ty
The issue is that after return res.status(403), the promise chain doesn't stop automagically. Eventually, it will hit res.status(200) and cause the error.
You can rewrite your promise chain a bit to prevent this. I'm not sure what the purpose of that User.update().exec() is, but I assume that you wanted to call it and also wait for its promise to get resolved before continuing:
exports.delete = function (req, res) {
Parking.findById(req.params.id).exec()
.then(function (parking) {
if (userController.ensureAuthorized(req, 'Director', parking.id)) {
return User.update(...).exec().then(function() {
return Parking.remove({_id: parking._id}).exec();
}).then(function() {
return res.status(200).json({msg: 'Ok ! Parkink remove'});
});
} else {
return res.status(403).send({msg: 'unauthorized'});
}
}).catch(function (err) {
return res.status(400).send(err);
});
};
Well there is no standard way of breaking the promise chain.
So I am going to throw an error to break the chain, and then handle that custom thrown error:
exports.delete = function (req, res) {
Parking.findById(req.params.id).exec()
.then(function (parking) {
if (userController.ensureAuthorized(req, 'Director', parking.id)) {
return parking;
}
else {
res.status(403).send({msg: 'unauthorized'});
throw new Error('BREAK_CHAIN'); // <-- intentionally throw error
}
})
.then(function (parking) {
User.update().exec();
return parking;
})
.then(function (parking) {
return Parking.remove({_id: parking._id}).exec();
})
.then(function () {
res.status(200).json({msg: 'Ok ! Parkink remove'});
})
.catch(function (err) {
if(err.message != 'BREAK_CHAIN') // <-- handle if error was intentionally thrown
return res.status(400).send(err);
});
};
just as an addition to the other answers given, I would recommend:
1) breaking things up into small parts
2) using throw as intended, to raise the error of non-authorization
function update (parking) {
User.update().exec()
.then(function () {
Parking.remove({_id: parking._id}).exec();
});
}
exports.delete = function (req, res) {
// auth needs req so we put it in scope
var auth = function (parking) {
if (!userController.ensureAuthorized(req, 'Director', parking.id)) {
throw(new Error(403));
}
return parking;
}
Parking.findById(req.params.id).exec()
.then(auth)
.then(update)
.then(function () {
res.status(200).json({msg: 'Ok ! Parkink remove'});
})
.catch(function (err) {
if (err.message === 403) {
return res.status(403).send({msg: 'unauthorized'});
}
return res.status(400).send(err);
});
};
I have this code with callbacks:
function getUserToken(data, callback) {
var password_sha256 = sha256(data.password);
getAppById(data.app_id).then(function(res) {
console.log("app"+res);
if (!res) {
console.log("No app");
callback(err, { meta: {
code: 403,
error_message: "There are no app with your id!"
} });
} else {
if (res.user_password == password_sha256) {
console.log("user found");
callback(err, { meta: { code: 200 },
token: password_sha256,
type: 1 });
return;
} else if (res.owner_password == password_sha256) {
console.log("owner found");
callback(err, { meta: { code: 200 },
token: password_sha256,
type: 0 });
} else {
console.log("user not found");
callback(err, { meta: {
code: 403,
error_message: "There are no users with your password!"
} });
}
}
});
}
I post some data using this function:
router.post('/api/login', (req, res) => {
db.getUserToken(req.body, function(err, result) {
console.log(result);
if (result.error) {
return res.status(403).send(result);
} else {
return res.status(200).send(result);
}
});
});
And then getUserToken found, for example, user, so I have "user found" in console log, but callback function in /api/login not working. Where is my error and how can I fix them?
Instead of callback, you can return a Promise, either native or using an external library like Kris Kowal Q
var Q = require('q');
function getUserToken(data) {
var deferred = Q.defer();
var password_sha256 = sha256(data.password);
getAppById(data.app_id).then(function(res) {
if (!res) {
deferred.reject("There are no app with your id!");
} else {
if (res.user_password == password_sha256) {
deferred.resolve({
token: password_sha256,
type: 1
});
} else if (res.owner_password == password_sha256) {
deferred.resolve({
token: password_sha256,
type: 0
});
} else {
console.log("user not found");
deferred.reject("There are no users with your password!");
}
}
})
.catch(function(error) {
deferred.reject(error);
});
return deferred.promise;
}
Then simply process or catch error when you post data
router.post('/api/login', (req, res) => {
db.getUserToken(req.body)
.then(function(result) {
res.status(200).send(result);
})
.catch(function(error) {
res.status(403).send(error);
});
});
Instead of using callback(err, data) you should use callback(null,data).This will give you required output.
I'm trying to convert my existing code using BlueBird, please suggest a best option to chain multiple request. Error happening in each callback needs to be redirected to rendered with different error.
request(option1, function (error, response, body) {
if (!error && response.statusCode == 200) {
var data= JSON.parse(body);
if(data.valid){
if(data.expired){
next();
} else {
request(option2, function (error2, response2, body2) {
var data2= JSON.parse(body2);
if(data2.valid) {
request(option3, function (error3, response3, body3) {
next();
})
} else {
res.json({error:'Error1'});
}
})
}
} else {
res.json({error:'Error2'});
}
} else {
res.json({error:'Error3'});
}
})
This is pretty straightforward, also note your current code doesn't handle errors in the second and third requests and this does:
var request = require("request-promise"); // request - converted to bluebird
request(option1).then(data=> {
if(!data.valid) throw Error("Error3");
if(data.expired) return;
return request(option2).then(JSON.parse);
}).then(data2 => {
if(!data2) return; // didn't need to fetch additional data
if(!data2.valid) throw Error("Error2");
return request(option3);
}).then(() => {
next();
}, e => {
res.json(error: e.message);
// better log this.
});
var rp = require('request-promise');
function handleError(err) {
res.json({
error: err.message
});
}
function parse(data) {
if (data) {
return JSON.parse(data);
}
}
rp(option1)
.then(parse)
.then(function (data) {
if (!data || !data.valid) {
throw Error('Error2');
}
if (data.expired) {
return;
}
return option2;
})
.then(rp)
.then(parse)
.then(function (data2) {
if (!data2 || !data2.valid) {
throw Error('Error1');
}
return option3;
})
.then(rp)
.then(parse)
.then(function () {
next();
})
.catch(handleError);
You don't need to manually check for statusCode but if you need to do so, first you have to add resolveWithFullResponse attribute to your option1 object, which allows you to receive the response object:
function checkStatusCode(response) {
if (response.statusCode !== 200) {
throw Error('Error3');
}
return response.body;
}
// add resolveWithFullResponse attribute to option1
option1.resolveWithFullResponse = true;
rp(option1)
.then(checkStatusCode)
.then(parse)
//...