I have lots of API data calls In the form of:
app.get('/getSomeData', function(req, res) {
//get parameters
dataService.getSomeData(param1, param2, commonCallback.bind(null, null, res));
});
var commonCallback = function (err, payload, res) {
if (err) {
console.log("server error ");
res.status(500).end();
return;
}
if (payload.messageType == 'errorMessage') {
res.status(401).json(payload);
} else {
res.json(payload);
}
}
and in DataService.js:
const getSomeData = function (param1, param2, callback) {
//do some work
if (err) {
callback(err);
return;
}
callback(null, payload);
}
exports.getSomeData = getSomeData;
but I get errors complaining that there are Cannot read property 'json' of null I don't think I'm using bind() correctly. But there doesn't seem to be many non-trivial examples out there.
What am I doing wrong?
Related
i have above api in TestRouter.js
TestRouter.js
router.get('/all', function(req, resp) {
var data = reportBo.getAll();
console.log(data);
resp.status(200);
resp.send(data);
return resp;
});
i am calling getAll() from TestRouter.js to TestDao.js.
it is working fine and can fetch the data and can print in console. but i am trying to send this result to TestRouter.js and i am trying to print it on console. but it is showing undefined.
TestDao.js
module.exports.getAll = function () {
var connection = myDB.get();
connection.collection('REPORTS').find({}).toArray(function (err, result) {
if (err) {
throw err;
} else {
//console.log(result);
return result;
}
});
};
module.exports.getAll = function (callback) {
var connection = myDB.get();
connection.collection('REPORTS').find({}).toArray(function (err, result) {
if (err) {
callback(err);
} else {
//console.log(result);
callback(null, result);
}
});
};
And in your router:
router.get('/all', function(req, resp) {
reportBo.getAll(function(err, data){
if(err){
resp.status(500);
} else {
resp.status(200);
resp.send(data);
}
});
});
This way of doing things with callbacks is quite common in Node JS. Also, there is a better way called Promises. You can read up on it.
I have written below code in one file:
models/exported.js
module.exports = {
processedList: function(store_name) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return console.error(err);
return value;
}).select('tid -_id');
}, // Export connection here
};
I have another file in routes
routes/exported.js
var exported = require('../models/exported.js');
var tradeIds = exported.processedList(storename);
console.log('simer'+tradeIds);
}
but I get undefined in console.log. If instead of return statement in processedlist I write console.log then the result gets console. But my requirement is to return data from model file to route file.
I am new to express and node js.
I guidance would be highly appreciated.
Acoording to your question, you want calling a function from route and get return response from your function to route. simple use callback functions.
models/exported.js
module.exports = {
processedList: function (store_name, callback) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) {
callback("error", err)
} else {
callback("success", value)
}
}).select('tid -_id');
}
}
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList('storename', function (err, results) {
if (err == 'error') {
console.log(err);
} else {
console.log(results);
}
});
You are trying sync operation in async environment. processedList may or may not have completed when you try to console log tradeIds. NodeJS would not wait for it to complete because it is asynchronous in nature (by design and it is not a bug). You can pass callback rather than executing this way.
models/exported.js
module.exports = {
processedList: function(store_name, cb) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return cb(err);
cb(null, value);
}).select('tid -_id');
}, // Export connection here
};
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList(storename, function(err, results) {
if (err) { console.log(err); }
console.log(results);
});
This makes sure that console.log happens only when processedList finishes execution.
this.queryMailApi = function(mailUrl, callback) {
request.get({url: mailUrl}, function (err, httpResponse, body) {
if (err) {
return console.error('post failed:', err);
} else
callback(body);
});
};
this.myCallBack = function(data) {
var emailData = data;
console.log(emailData);
}
This is my function + callback to get the value. I want to return it to a function call similar to how you would do this.
var x = shared.queryMailApi(mailApiUrl, shared.myCallBack);
To be used later in code. I've read a ton of things about asynchronous Nodejs stuff which means I can't actually do this... but there has to be a way.
I didn't try this, but I think you should be able to do this in in this way with a promise.
this.queryMailApi = function(mailUrl) {
var deferred = protractor.promise.defer();
request.get({url: mailUrl}, function (err, httpResponse, body) {
if (err) {
deferred.reject(err);
return console.error('post failed:', err);
}
deferred.resolve(body);
});
return deferred.promise
};
this
.queryMailApi('example#mail.com')
.then(function(response) {
console.log(response);
});
If this doesn't work, you may take a look webdriver.WebDriver.wait. This may be useful.
I'm having an annoying as hell problem with 'Error: Can't set headers after they are sent.' in Express. This code originally worked using Restify rather than Express and I have been having this problem in one form or another since converting it.
The code makes 2 asynchronous requests to another API (edited out) and merges the results into a single JSON before storing it in MongoDB.
Any insight would be appreciated as I have tried all I can think of and have no idea why the same function would work in Restify and not Express with the appropriate changes.
Please don't comment on the Pyramid of Doom, I know it's not ideal, but that's not the focus here ;)
app.post('/rest/test', jsonParser, /*keycloak.protect(),*/ function (req, res, next) {
var requestObj = req.body;
try {
/* run async requests in parallel */
async.parallel([
function asyncReqV3(callback) {
request.post(reqUrl1, option_v3, function(err, response, body) {
if(err) {
console.log(err);
callback(true);
return;
} else {
callback(false, body);
}
});
},
/* v4 async request */
function asyncReqV4(callback) {
request.post(reqUrl2, option_v4, function(err, response, body) {
if(err) {
console.log(err);
callback(true);
return;
} else {
callback(false, body);
}
});
},
],
/* Collate results and send */
function collateResults(err, results) {
if(err) {
console.log(err);
return res.status(500).send("Server Error");
} else {
/* Merging results */
var hash = new Map();
results[0].body.krResult.forEach(function(obj) {
hash.set(obj.word, obj);
});
var final = results[1].body.data.map(function(obj) {
return Object.assign(hash.get(obj.word) || {}, obj);
});
var final_results = final.slice(0, 250).map(function(obj) {
return {
thing1: obj.something,
thing2: obj.somethingElse
}
});
/* Store results in DB */
db.results.insert({
request: requestObj,
response: final_results
});
res.status(200).send(final_results);
}
});
}
catch(e) {
console.log(e);
res.status(500).send({});
}
return next();
});
At the end of your route callback, remove:
return next();
You don't need it here and this line will always be executed before the async.parallel is done (collateResults in your code). You're quite likely sending a response in the subsequent routes and then again after your two requests are done.
I'm trying to design a webpage. I have a function that I call to get all info needed for an individual's home page. A snippet of the code is:
exports.getHomePageData = function(userId, cb) {
var pageData = {};
pageData.userFullName = dbUtil.findNameByUserId(userId, function(err){
if (err) cb(err);
});
pageData.classes = dbUtil.findUserClassesByUserId(userId, function(err){
if (err) cb(err);
});
cb(pageData);
}
The problem I'm having is that the cb(pageData) is being called before I even finish setting the elements.
I've seen that people use the async library to solve this, but I was wondering if there was any other way for me to do it without needing more modules.
One possible approach:
exports.getHomePageData = function(userId, cb) {
var pageData = {},
filler = function() {
if ('userFullName' in pageData
&& 'classes' in pageData)
cb(null, pageData);
};
dbUtil.findNameByUserId(userId, function(err, name) {
if (err) {
cb(err);
return;
}
pageData.userFullName = name;
filler();
});
dbUtil.findUserClassesByUserId(userId, function(err, classes) {
if (err) {
cb(err);
return;
}
pageData.classes = classes;
filler();
});
}
It looks like dbUtil.findUserClassesByUserId and dbUtil.findNameByUserId are asynchronous methods; that usually indicates that they do not return a value, and instead use the callback to give you the data.
Both functions are most likely expecting a signature like follows:
function(err, data) {
// if err is set, an error occurred, otherwise data is set with the result
}
Thus, your function should look like this instead:
exports.getHomePageData = function(userId, cb) {
dbUtil.findNameByUserId(userId, function(err, userFullName){
if (err) {
cb(err);
return;
}
dbUtil.findUserClassesByUserId(userId, function(err, classes){
if (err) {
cb(err);
return;
}
var pageData = {
userFullName: userFullName,
classes: classes
};
cb(pageData);
});
});
}