I know node is all about async stuff but I want to do things in serial mode as follows:
make api request > convert body xml to JSON.stringify > pass string to template.
request.get({url:url, oauth:oauth}, function(err, res, body){
parseString(body, function(err, result){
output = JSON.stringify(result);
res.render('home', { title: 'Fantasy Home',
output: output });
});
});
Now I want to do this in sequence, but with all the callbacks I'm confused.
res.render doesn't work nested inside callbacks because the res object doesn't exist. Having it outside won't work because it'll run before the callbacks execute so you'd get "undefined" for output.
There has to be a way to do things in sequential order. Why is everything a callback?? Why can't these functions just return a regular non-callback result?
How can I make this work?
The others fail to mention why your res.render does not work.
You probably have something like this:
app.get('/', function(req, res, next) { // You need the res here to .render
request.get({url:url, oauth:oauth}, function(err, res, body){ // But you are using this res instead, which does not have the render method
parseString(body, function(err, result){
output = JSON.stringify(result);
res.render('home', { title: 'Fantasy Home',
output: output });
});
});
});
Read the comments in the code. So your solution is, use res.render from the request handler, rename res in the request.get callback to something else.
You should use middlewares, also promises is better thing to work with async in node, but I'll show you with callbacks. It is strongly suggested to not to block your thread with synchronous calls! Since node.js is single threaded. next() is an callback here so middleware won't allow execution of main route function (with res.render) until next() is called. You can pass as many middlewares as you wish.
app.use('/user/:id', middleware, (req, res) => {
//here you'll find your data
console.log(req.callData);
res.render(view, req.callData);
}
middleware(req, res, next) => {
dotheCall(dataToPass, (err, cb) => {
req.callData = cb;
// remember about handling errors of course!
return next();
})
}
JavaScript is single threaded if we use synchronous code then that will itself a big problem around response time (node.js) and all. Everything is implemented with callback fashion due to the benefit of event loop.
You can take a deep understanding of event loop : https://youtu.be/8aGhZQkoFbQ (Very good explaination)
You can use Promisification for the scenario you want to implement : http://bluebirdjs.com/docs/getting-started.html
request.get({url:url, oauth:oauth}, function(err, res, body) {
// Note :: This is Promisified Function
return parseString(body)
.bind(this)
.then(function(result) {
output = JSON.stringify(result);
res.render('home', {title: 'Fantasy Home', output: output });
return true;
})
.catch(function(error)
{
// Error Handling Code Here
// Then send response to client
});
});
You can implement promisified function using the following approach
function parseString(body) {
var Promise = require("bluebird");
return new Promise(function(resolve,reject) {
// Your Parsing Logic here
if(is_parsed_successfully) {
return resolve(parsed_data);
}
return reject(proper_err_data);
})
}
Related
So in Node we use async functions. And to do that we use callback functions as parameters. But how do I execute the final function after which I want to terminate the code? Just pass the empty function? Here's example:
fs.mkdir('stuff', function(){
fs.readFile('readMe.txt', 'utf8', function(err, data) {
fs.writeFile('./stuff/writeMe.txt', data);
});
});
mkdir has callback function - all fine
readFile has callback function - all fine
writeFile has NOT callback function because that's the last thing I want to do, but then I get an error in console:
"DeprecationWarning: Calling an asynchronous function without callback is deprecated."
Should I every time I do that, pass an empty function as a callback to avoid the error? What's the best practice for this?
Should I every time I do that, pass an empty function as a callback to avoid the error?
No.
What's the best practice for this?
Pass in a function and handle any errors it reports. You also need to handle errors from mkdir and readFile, which currently you're ignoring.
E.g.:
fs.mkdir('stuff', function(err) {
if (err) {
// Do something with the fact mkdir failed
} else {
fs.readFile('readMe.txt', 'utf8', function(err, data) {
if (err) {
// Do something with the fact readFile failed
} else {
fs.writeFile('./stuff/writeMe.txt', data, function(err) {
if (err) {
// Do something with the fact writeFile failed
}
});
}
});
}
});
...which is a fair example of callback hell, which is part of the motivation of using promises instead. You could promisify the fs API (using any of several libs, such as promisify) and do it like this:
fsp.mkdir('stuff')
.then(() => fsp.readFile('readMe.txt', 'utf8'))
.then(data => fsp.writeFile('./stuff/writeMe.txt', data))
.catch(err => {
// Do something with the fact something failed
});
...where fsp is a placeholder for the promisified fs API.
In Node 8.x+, you could use async/await to write synchronous-looking code with those promisified APIs:
// This must be inside an `async` function
try {
fsp.mkdir('stuff');
const data = await fsp.readFile('readMe.txt', 'utf8');
await fsp.writeFile('./stuff/writeMe.txt', data);
} catch (err) {
// Do something with the fact something failed
}
You can use writeFileSync instead.
fs.mkdir('stuff', function(){
fs.readFile('readMe.txt', 'utf8', function(err, data) {
fs.writeFileSync('./stuff/writeMe.txt', data);
});
});
i am new to nodejs, this might seem pretty trivial but i am having trouble retrieving data from a function that returns a promise. The response from the middleware is sent back to the front end. Here is my code
// middleware
app.get('/player', function(req, res) {
//data i want to return
res.send(getPlayerStats.getPlayerId(req.query.name)));
});
//getPlayerStats.js
var getPlayerId = function(name) {
return start(name)
.then(getPlayerInGame)
.then(getPlayerStats)
.then(getPlayers);
//.then(sendToSingular)
}
//getplayers function
var getPlayers = function(data) {
return data;
}
I'm i sending the data back the wrong way? The response i see at the front end is an object with prototype as the only property. I can print out the data in getPlayers() and i see it is working fine.
That's because you're passing the promise itself into res.send.
res.send(/* You are passing a promise here */);
What you should do is wait for the promise to resolve with the data and then send that data:
getPlayerStats.getPlayerId(req.query.name).then(function(data) {
res.send(data);
});
And I always recommend to finish your promise chain with a catch() to make sure errors are handled:
getPlayerStats.getPlayerId(req.query.name)
.then(function(data) {
res.send(data);
})
.catch(function(error){
res.status(500).send('Some error text');
});
When you write middleware it sounds like you want the player id to be available for other actions so in addition to the other comments here:
app.get('/player/*', function(req, res, next) {
//data i want to return
getPlayerStats.getPlayerId(req.query.name))).then(function(id){
res.locals.playerId = id;
next();
});
});
app.get('/player/action', function(req, res){
res.send(res.locals.playerId); //or use it for further processing
});
I want to kinda override default next in Restify. E.g. now i have code like
server.post('/names', function (req, res, next) {
names = req.params.names;
if (!Array.isArray(names)) {
return next(new restify.errors.BadRequestError('names field is wrong or missing'));
}
res.send({ code: "OK" });
return next();
});
I want it to be just
server.post('/names', function (req, res, next) {
names = req.params.names;
if (!Array.isArray(names)) {
return next(new restify.errors.BadRequestError('names field is wrong or missing'));
}
// Add names to DB
return next();
});
Where next (for non-error results) is like
function next(res) {
if (!body.hasOwnProperty("code")) {
body["code"] = "OK";
}
res.send(body);
}
What is the best way to implement this?
I think you may be looking for a handler that executes after all other handlers in the chain are done. Consider the "after" event handler. In the documentation they show an example for audit logging.
You should be able to use that same thing to update the response body as needed. The code might look something like this...
server.on('after', function (request, response, route, error) {});
Keep in mind, this still requires you to return next(); from all of the other handlers in the chain.
I have a NodeJS server and a helper function that is making a HTTP request, but when I make the call for the function, it comes up as undefined. The call is being made in a callback, so I don't think that there is a problem with the Async part of it.
This is the server.js
console.log(dictionary('wut'));
And this is the function dictionary.
if(dictionary[word]===undefined){
request({
url:"https://mashape-community-urban-dictionary.p.mashape.com/define?term="+word,
headers:{
'X-Mashape-Key':'KEY HERE',
'Accept':'text/plain'
}
}, function(err, response, body){
if(!err && response.statusCode==200){
var info = JSON.parse(body);
console.log(info.list[0].definition);
return info.list[0].definition;
}
});
} else {
return dictionary[word];
}
Where word is the word that is being passed to the function.
Edit: I forgot to mention that the dictionary function has
module.exports = function(word){
The return statements are supposed to give the module the value from the callback. Sorry about that, that's kind-of important information.
You're going to want to use a callback method with your helper method.
So your helper defintion would look like this:
function dictionary(word, callback) {
request({}, function(err, res, body) {
if (err) {
return callback(err);
}
callback(null, body);
});
}
And your call would become:
dictionary('wut', function(err, result) {
if (err) {
return console.error('Something went wrong!');
}
console.log(result);
});
This is obviously a very simple implementation, but the concept is there. Your helpers/ modules/ whatever should be written to accept callback methods that you can then use to bubble up errors and handle them in the appropriate place in your application. This is pretty much the standard way to do things in Node.
Here is how you could call your helper using a simple Express route:
router.route('/:term')
.get(function(req, res) {
dictionary(req.params.term, function(err, result) {
if (err) {
return res.status(404).send('Something went wrong!');
}
res.send(result);
});
});
From my viewpoint, it looks like that request library you're using was designed asynchronous. This means that you should handle the data inside of the callback function.
For instance:
function handle(data) {
// Handle data
console.log(data)
}
if(dictionary[word]===undefined){
request({
url:"https://mashape-community-urban-dictionary.p.mashape.com/define?term="+word,
headers:{
'X-Mashape-Key':'KEY HERE',
'Accept':'text/plain'
}
}, function(err, response, body){
if(!err && response.statusCode==200){
var info = JSON.parse(body);
console.log(info.list[0].definition);
handle(info.list[0].definition)
}
});
} else {
handle( dictionary[word] )
}
You didn't provide enough information for me to set this up correctly. But hopefully this gives you an idea on what you need to do.
To elaborate on why you should set it up this way:
The request function appears to be asynchronous, so keep it how it was designed.
You're returning inside of the callback, so your outer dictionary function isn't getting that returned data, the callback is.
Since the request function was designed async, there isn't a way to return the data to the dictionary without forcing it to be synchronous (which isn't advised). So you should restructure it to be handled inside of the callback.
(Another little note, you should use typeof dictionary[word] === "undefined", because I believe JavaScript sometimes throws an error otherwise.)
This is how I am currently getting data from mongodb:
users.get(base_URL, (req, res) => {
UserModel.find({}, (err, docs) => {
res.render("Users/index", {
title: "All Users here",
user_list: docs
});
});
});
Now, as you can see this is an express application. What I would like, is to simple call a function so that I can get the value from the docs variable inside the mongodb model callback. How do I do this, ideally, I want to see something like this:
users.get(base_URL, (req, res) => {
res.render('<some_jade_file_here>', {
title: "Yes, got it right",
user_list: getAllUsers();
});
});
Ideally, I just want to call a function. How can I do this, since having to put render inside of a mongodb call is a problem, since you may want to query a bunch of things from the database, and it might not even be just one database. I'm struggling a little since I'm not all that used to callbacks.
Any help would be deeply appreciated. If you're wondering about this syntax () => {}, thats just an anonymous function in typescript.
You can't do it without callbacks, but you can use an async flow control library like async to help manage the nest of callbacks. In this case you probably want to use async.parallel.
Using that you can do something like:
users.get(base_URL, (req, res) => {
var data = {
title: "Yes, got it right"
};
async.parallel([
(callback) => {
UserModel.find({}, (err, docs) {
data.user_list = docs;
callback(err);
});
},
(callback) => {
// Other query that populates another field in data
}
], (err, results) => {
// Called after all parallel functions have called their callback
res.render('<some_jade_file_here>', data);
});
});