I'm learning Node.js and I'm working on a sample app. I've a question why is that I always receive http 400 even if it is a successful response.
abcRoutes.get('/fetch', function (req, res) {
abc.getInfo(req,(err,response) =>{
if(err){
res.status(400).send(err);
}else{
res.status(200).send(response);
}
})
});
var getInfo = (req, callBack) => {
***some processing***
if (err) {
callBack(err);
} else {
callBack(result);
}
});
client.close();
}
})
}
The error is here:
var getInfo = (req, callBack) => {
//* **some processing***
if (err) {
callBack(err)
} else {
callBack(null, result) <---
}
}
Using callback pattern you need to keep in mind that the first argument is always an error.
You should set the first argument (err) to null on success:
if (err) {
callBack(err);
}
else {
callBack(null, result);
}
I am attempting to do what I've previously done in c# and asp.net webforms and execute a number of insert stored procedures, some of which are in loops, in a transaction. I am now trying to do so in my angular application through node.js with the mssql package. What I have so far is as follows.
//Insert Change Record
router.post('/insertChange', (req, res) => {
const transaction = new sql.Transaction(conn);
transaction.begin(err => {
let rolledBack = false;
transaction.on('rollback', aborted => {
rolledBack = true;
})
const request = new sql.Request(transaction);
request.input('ChangeTitle', req.body.changeTitle);
request.input('TypeId', req.body.typeId);
request.input('DateSubmitted', req.body.dateSubmitted);
request.input('TargetDate', req.body.targetProductionDate);
request.input('ChangeSponsor', req.body.changeSponsor);
request.input('UATDate', req.body.dateReadyUAT);
request.input('ChangeSponsorEmail', req.body.changeSponsorEmail);
request.input('ClarityId', req.body.clarityId);
request.input('ChangeDescription', req.body.changeDescription);
request.input('ComponentName', req.body.componentName);
request.input('ComponentDescription', req.body.componentDescription);
request.input('ReasonForChange', req.body.reasonForChange);
request.input('ComponentREplacing', req.body.componentReplacing);
request.input('DependentChange', req.body.dependentChange);
request.input('InstallOption', req.body.installOption);
request.input('RebootRequired', req.body.rebootRequired);
request.input('UserIntervention', req.body.userIntervention);
request.input('Activation', req.body.activation);
request.input('ContingencyPlan', req.body.contingencyPlan);
request.input('AdditionalInformation', req.body.additionalInformation);
request.input('PerformanceImpact', req.body.applicationPerformance);
request.input('IsPCoERequired', req.body.pcoeTesting);
request.input('IsCanadianRetailBranch', req.body.pbsTesting);
request.input('BusinessAppImpact', req.body.businessApplication);
request.input('NetworkImpact', req.body.networkPerformance);
request.input('NewInfrastructure', req.body.newInfrastructure);
request.input('LogonTime', req.body.logonTime);
request.input('AdditionalTechnicalInformation', req.body.additionalAssessmentInfo);
request.input('IsProdIssue', req.body.isProdIssue);
request.input('ProdIssue', req.body.productionIssue);
request.input('ProdIncidentNum', req.body.incidentNumbers);
request.input('IsMajorChange', req.body.isMajorChange);
request.input('HasRequiredTesting', req.body.hasRequiredTesting);
request.input('HasPackageSubmit', req.body.hasPackageSubmit);
request.input('SignOffETA', req.body.signoffETA);
request.input('SpecificTesting', req.body.specificTesting);
request.input('SpecificPilot', req.body.specificPilot);
request.input('PilotInfo', req.body.pilotTransits);
request.input('UserChanges', req.body.userDifferences);
request.input('ServiceDeskProcedure', req.body.procedureSupport);
request.input('SupportCallFlowId', req.body.supportCallFlow);
request.input('OverallChangeStatus', 1);
let changeId = request.output('changeId', sql.Int);
request.execute('dbo.InsertChange').then(function (result) {
console.dir(result);
}).catch(function (err) {
console.dir(err);
});
async.each(
req.body.changeType
,function iterator(item, next) {
const requestCT = new sql.Request(transaction);
requestCT.input('ChangeId', changeId);
requestCT.input('TypeOfChangeId', item.typeOfChangeId);
requestCT.input('Description', item.description);
requestCT.execute('dbo.InsertTypeOfChange').then(function (result) {
console.dir(result);
next();
}).catch(function (err) {
console.dir(err);
});
})
async.each(
req.body.serviceImpacted
,function iterator(item, next) {
const requestSI = new sql.Request(transaction);
requestSI.input('ChangeId', changeId);
requestSI.input('ServicesImpactedId', item.serviceImpactedId);
requestSI.execute('dbo.InsertImpactedService').then(function (result) {
console.dir(result);
next();
}).catch(function (err) {
console.dir(err);
});
})
async.each(
req.body.businessImpacted
,function iterator(item, next) {
const requestBI = new sql.Request(transaction);
requestBI.input('ChangeId', changeId);
requestBI.input('BusinessImpactedId', item.businessImpactedId);
requestBI.execute('dbo.InsertImpactedBusiness').then(function (result) {
console.dir(result);
next();
}).catch(function (err) {
console.dir(err);
});
})
async.each(
req.body.criticalApp
,function iterator(item, next) {
const requestCA = new sql.Request(transaction);
requestCA.input('ChangeId', changeId);
requestCA.input('CriticalBankingId', item.criticalId);
requestCA.input('Description', item.description);
requestCA.execute('dbo.InsertCriticalBankingApp').then(function (result) {
console.dir(result);
next();
}).catch(function (err) {
console.dir(err);
});
})
async.each(
req.body.testStages
,function iterator(item, next) {
const requestTS = new sql.Request(transaction);
requestTS.input('ChangeId', changeId);
requestTS.input('TestStageId', item.testStageId);
requestTS.input('TestDate', item.testDate);
requestTS.input('Description', item.description);
requestTS.execute('dbo.InsertChangeTest').then(function (result) {
console.dir(result);
next();
}).catch(function (err) {
console.dir(err);
});
})
if (err) {
if (!rolledBack) {
transaction.rollback(err => {
console.dir(err);
// ... error checks
})
}
} else {
transaction.commit(err => {
console.dir(err);
// ... error checks
})
}
})
});
There really isn't a heck of a lot of material online anywhere for processing transactions with stored procedures, and even less for big transactions like this. But the error I'm getting is the following multiple times in my terminal log.
{ TransactionError: Can't acquire connection for the request. There is another request in progress.
at Transaction.acquire (C:\Users\Redirection\meecd26\Documents\GitRepo\td-angular-starter\node_modules\mssql\lib\base.js:740:30)
at Immediate._query.err [as _onImmediate] (C:\Users\Redirection\meecd26\Documents\GitRepo\td-angular-starter\node_modules\mssql\lib\msnodesqlv8.js:417:19)
at runCallback (timers.js:781:20)
at tryOnImmediate (timers.js:743:5)
at processImmediate [as _immediateCallback] (timers.js:714:5) code: 'EREQINPROG', name: 'TransactionError' }
This certainly suggests that I'm performing the transaction improperly.
Would someone be able to help guide me as to how I can improve and fix this?
Edit: Made changes to my code to reflect what I found here, as well as a few changes to my first insert. While my first insert does work, I'm still getting the repeated errors above, so now I know my problems are with how I'm implementing the inserts inside of loops. Is there a way I can close the connection upon each insert? Would that be the approach I should try and take?
I ended up getting it working, and although my understanding of how everything works admittedly hasn't improved much at all, I can at least post what I have in hopes of others hopefully finding it helpful.
router.post('/insertChange', (req, res) => {
console.log("Beginning of POST, before initializing transaction");
let changeId;
let mainInsert = false;
beginTransaction(function (err, rollback, transaction) {
if (err) {
// return cb(err);
}
let request = new sql.Request(transaction);
// request.verbose = true;
request.input('ChangeTitle', req.body.ChangeTitle);
request.input('TypeId', req.body.TypeId);
request.input('DateSubmitted', req.body.DateSubmitted);
request.input('TargetDate', req.body.TargetDate);
request.input('ChangeSponsor', req.body.ChangeSponsor);
request.input('UATDate', req.body.UATDate);
request.input('ChangeSponsorEmail', req.body.ChangeSponsorEmail);
request.input('ClarityId', req.body.ClarityId);
request.input('ChangeDescription', req.body.ChangeDescription);
request.input('ComponentName', req.body.ComponentName);
request.input('ComponentDescription', req.body.ComponentDescription);
request.input('ReasonForChange', req.body.ReasonForChange);
request.input('ComponentReplacing', req.body.ComponentReplacing);
request.input('DependentChange', req.body.DependentChange);
request.input('InstallOption', req.body.InstallOption);
request.input('RebootRequired', req.body.RebootRequired);
request.input('UserIntervention', req.body.UserIntervention);
request.input('Activation', req.body.Activation);
request.input('ContingencyPlan', req.body.ContingencyPlan);
request.input('AdditionalInformation', req.body.AdditionalInformation);
request.input('PerformanceImpact', req.body.PerformanceImpact);
request.input('IsPCoERequired', req.body.IsPCoERequired);
request.input('IsCanadianRetailBranch', req.body.IsCanadianRetailBranch);
request.input('BusinessAppImpact', req.body.BusinessAppImpact);
request.input('NetworkImpact', req.body.NetworkImpact);
request.input('NewInfrastructure', req.body.NewInfrastructure);
request.input('LogonTime', req.body.LogonTime);
request.input('AdditionalTechnicalInformation', req.body.AdditionalTechnicalInformation);
request.input('IsProdIssue', req.body.IsProdIssue);
request.input('ProdIssue', req.body.ProdIssue);
request.input('ProdIncidentNum', req.body.ProdIncidentNum);
request.input('IsMajorChange', req.body.IsMajorChange);
request.input('HasRequiredTesting', req.body.HasRequiredTesting);
request.input('HasPackageSubmit', req.body.HasPackageSubmit);
request.input('SignOffETA', req.body.SignOffETA);
request.input('SpecificTesting', req.body.SpecificTesting);
request.input('SpecificPilot', req.body.SpecificPilot);
request.input('PilotInfo', req.body.PilotInfo);
request.input('UserChanges', req.body.UserChanges);
request.input('ServiceDeskProcedure', req.body.ServiceDeskProcedure);
request.input('SupportCallFlowId', req.body.SupportCallFlowId);
request.input('OverallChangeStatus', 1);
request.output('changeId', sql.Int);
request.execute('dbo.InsertChange', function (err, callback) {
if (err) {
console.dir(err);
rollback(err);
res.status(400).send("Failed to submit change form.");
} else {
mainInsert = true;
}
if (callback) {
changeId = +callback.returnValue;
}
if (mainInsert) {
async.each(
req.body.changeType, function iterator(item, next) {
request = new sql.Request(transaction);
request.input('ChangeId', changeId);
request.input('TypeOfChangeId', item.typeOfChangeId);
request.input('Description', item.description);
request.execute('dbo.InsertTypeOfChange', function (err, callback) {
if (err) return next(err);
console.dir(callback);
next();
})
}, function fin(err) {
if (err) {
rollback(err);
return; //done
}
})
async.each(
req.body.serviceImpacted, function iterator(item, next) {
request = new sql.Request(transaction);
request.input('ChangeId', changeId);
request.input('ServicesImpactedId', item.serviceImpactedId);
request.execute('dbo.InsertImpactedService', function (err, callback) {
if (err) return next(err);
console.dir(callback);
next();
})
}, function fin(err) {
if (err) {
rollback(err);
return; //done
}
})
async.each(
req.body.businessImpacted, function iterator(item, next) {
request = new sql.Request(transaction);
request.input('ChangeId', changeId);
request.input('BusinessImpactedId', item.businessImpactedId);
request.execute('dbo.InsertImpactedBusiness', function (err, callback) {
if (err) return next(err);
console.dir(callback);
next();
})
}, function fin(err) {
if (err) {
rollback(err);
return; //done
}
})
async.each(
req.body.criticalApp, function iterator(item, next) {
request = new sql.Request(transaction);
request.input('ChangeId', changeId);
request.input('CriticalBankingId', item.criticalId);
request.input('Description', item.description);
request.execute('dbo.InsertCriticalBankingApp', function (err, callback) {
if (err) return next(err);
console.dir(callback);
next();
})
}, function fin(err) {
if (err) {
rollback(err);
return; //done
}
})
async.each(
req.body.testStages, function iterator(item, next) {
request = new sql.Request(transaction);
request.input('ChangeId', changeId);
request.input('TestStageId', item.testStageId);
request.input('TestDate', item.testDate);
request.input('Description', item.description);
request.execute('dbo.InsertChangeTest', function (err, callback) {
if (err) return next(err);
console.dir(callback);
next();
})
}, function fin(err) {
if (err) {
rollback(err);
return; //done
}
else {
transaction.commit(function (err) {
if (err) {
console.error('Transaction commit error: ', err);
res.status(400).send("Failed to submit change form.");
} else {
console.error('Transaction commit success');
res.send({ "Response": "Success", "Message": "Change form successfully submitted." });
}
});
}
})
}
});
})
});
I have multiple res.send in one route, how can I append them all into one and send the accumulated list at the end?
I prefer to do it in the following form:
{
"writer": {success message},
"archive": {success message},
...
}
and another one like above for the list errors.
here is the code:
router.post('/some/route', function (req, res) {
if (req.isLoggedIn()) {
return res.status(403).json({});
}
MyModel.findById(req.user._id,function (err, data) {
if(err || data.rights !== 'super'){
return res.status(403).json({});
}
if(req.body.writer){
Books.update(
{ writer : req.body.id},
{ $set : { writer : req.body.writer} },
function (err) {
if(err){
res.status(500).send(err);
}
else{
res.status(200).send('updated successfully.');
}
}
);
}else{
Books.remove({writer: req.body.id}, function(err){
if (err){ return console.log(err)}
});
}
MetaInfo.findOneAndRemove({_id: req.body.id}, function (err, data) {
console.log(err);
});
Archive.findOne({_id: req.body.id},function (err, data) {
smtpTransporter.sendMail({...}, function (error, response) {
if (error) {
console.log(error);
} else {
console.log("Mail sent");
}
smtpTransporter.close();
});
data.remove();
if (err) {
console.log(err);
return res.status(200).json({
success: false,
message: 'server error',
err: err
});
}
res.status(200).json({
success: true
});
})
});
});
I assume your problem are the asynchronous calls to the database.
So best take a library of your choice (for example async) and do your async processes, in the callback then finally send your result.
Your result could look like this:
async.parallel([
function(callback) { ... },
function(callback) { ... }
], function(err, results) {
// send your result here
});
Note that if you are using .parallel the final callback will be immediatly called if one of the promises fails. see the docu
I am writing this code as a project for a customer
and when i go to a show route i got this 500 internal server error
http.get('/files/:id', function(req, res) {
var vid;
var pap;
Videos.find({}, function(err, videos) {
if (err) {
console.log(err);
} else {
vid = videos;
}
});
Papers.find({}, function(err, file) {
if (err) {
console.log(err);
} else {
pap = file;
}
});
Material.findById(req.params.id, function(err, found) {
if (err) {
console.log(err);
} else {
res.render('files', {
file: pap,
video: vid,
current: found
});
}
});
});
this is my show route code.
Note : if i reload the page the error is gone and the page open.
The reason is you need to wait for all the database queries to finish before rendering. In your code, it is possible for the page to render before the other two queries have completed and returned their data. The good news is that Mongoose supports Promises for asynchronous functions.
http.get('/files/:id', function(req, res) {
Promise.all([
Videos.find({}).exec(),
Papers.find({}).exec(),
Material.findById(req.params.id).exec()
]).then( ([video, paper, material]) => {
res.render('files', {
file: paper,
video: video,
current: material
});
}).catch( error => console.log(error) );
});
The functions you're using with Mongoose are asynchronous in nature; the variables vid and pap are not initialized when you run res.render. When you attempt to use those variables in your frontend (template like Jade, Handlebars EJS, I don't know what you're using), they are undefined, and subsequently cause the 500 error. You'll need to run the functions such that the results of all Mongoose queries are available to res.render when it runs; either using an async NodeJS library, or calling each function within one another and then calling res.render at the end.
Solution 1: Using async Node module
var async = require('async');
async.parallel([
// Each function in this array will execute in parallel
// The callback function is executed once all functions in the array complete
function (cb) {
Videos.find({}, function(err, videos) {
if (err) {
return cb(err);
} else {
return cb(null, videos);
}
});
},
function (cb) {
Papers.find({}, function(err, papers) {
if (err) {
return cb(err);
} else {
return cb(null, papers);
}
});
},
function (cb) {
Material.findById(req.params.id, function(err, found) {
if (err) {
return cb(err);
} else {
return cb(null, found);
}
});
}
], function (err, results) {
if (err) {
// If any function returns an error
// (first argument), it will be here
console.log(err);
}
else {
// Even though the functions complete asynchronously,
// the order in which they are declared in the array
// will correspond to the position in the array
// if it returns anything as a second argument.
var videos = results[0];
var files = results[1];
var found = results[2];
res.render('files', {
file: files,
video: videos,
current: found
});
}
});
Solution 2: Nested Callbacks
Videos.find({}, function(err, videos) {
var vid = videos;
if (err) {
console.log(err);
} else {
Papers.find({}, function(err, file) {
var pap = file;
if (err) {
console.log(err);
} else {
Material.findById(req.params.id, function(err, found) {
if (err) {
console.log(err);
} else {
res.render('files', {
file: pap,
video: vid,
current: found
});
}
});
}
});
}
});
I'm a little new to Express/Node.js/Mongoose and I've ran into callback hell. What I'm trying to do is get a request in to this API URL /page/module/add/:id, if successful call buildMod(data), then that function calls getMod(data), and then that function calls writeMod(data) and eventually I want to pass the true value right back up to my router.
Once I have the response, I want to return it. I've searched online and there's not many similar situations--I personally think I've got myself in too deep...
router.get('/page/module/add/:id', function(req, res) {
Client.find({"emailAddress": emailAddress, "sequence.slug": pageSlug},
{"emailAddress": 1, "sequence.$": 1}, function (err, data) {
if (!err) {
res.statusCode = 200;
buildMod(data);
return res.json(data);
} else {
res.statusCode = 500;
log.error('Internal error(%d): %s', res.statusCode, err.message);
return res.json({
error: 'Server error'
});
}
}).select('sequence emailAddress domain');
});
function buildMod(data) {
getMod(data);
}
function getMod(data) {
Module.find({ 'module_id': moduleNumID }, function (err, module) {
if(!module) {
return false;
}
if (!err) {
writeMod(data);
} else {
return false;
}
});
}
function writeMod(data) {
fs.appendFile(location, content, function(err) {
if (err) throw err;
return true;
});
}
I know the declarations are wrong for the functions for callbacks but I've been trying and I just can't seem to get past this stage. I'm sure this is definitely possible, any help is really appreciated!
fs.appendFile is asynchronous and you can not return from asynchronous calls.
Make use of callback
router.get('/page/module/add/:id', function(req, res) {
Client.find({
"emailAddress": emailAddress,
"sequence.slug": pageSlug
}, {
"emailAddress": 1,
"sequence.$": 1
}, function(err, data) {
if (!err) {
res.statusCode = 200;
buildMod(data, function(data) {
res.json(data);
});
} else {
res.statusCode = 500;
log.error('Internal error(%d): %s', res.statusCode, err.message);
return res.json({
error: 'Server error'
});
}
}).select('sequence emailAddress domain');
});
function buildMod(data, cb) {
getMod(data, cb);
}
function getMod(data, cb) {
writeMod(data, cb);
}
function writeMod(data, cb) {
fs.appendFile(location, content, function(err) {
if (err) throw err;
cb(true);
});
}