My controller is using the request package to make server-side HTTP requests to another API. My question is how can I make MULTIPLE of these requests? Here is my current code:
** UPDATED CODE **
module.exports = function (req, res) {
var context = {};
request('http://localhost:3000/api/single_project/' + req.params.id, function (err, resp1, body) {
context.first = JSON.parse(body);
request('http://localhost:3001/api/reports/' + req.params.id, function (err, resp2, body2) {
context.second = JSON.parse(body2); //this line throws 'SyntaxError: Unexpected token u' error
res.render('../views/project', context);
});
});
};
I need to make two more of those calls and send the data returned from it to my template...
Can someone help?
Thanks in advance!
function makePromise (url) {
return Promise(function(resolve, reject) {
request(url, function(err, resp, body) {
if (err) reject(err);
resolve(JSON.parse(body));
});
});
}
module.exprts = function (req, res) {
let urls = ['http://localhost:3000/api/1st',
'http://localhost:3000/api/2st',
'http://localhost:3000/api/3st'].map((url) => makePromise(url));
Promise
.all(urls)
.then(function(result) {
res.render('../views/project', {'first': result[0], 'second': result[1], 'third': result[2]});
})
.catch(function(error){
res.end(error);
});
}
You can use Promise lib in latest nodejs.
Simple solution
Nest request calls. This is how you can handle the dependency between requests. Just make sure your parameters are unique across scopes if needed.
module.exports = function (req, res) {
var context = {};
request('http://localhost:3000/api/1st', function (err, resp1, body) {
var context.first = JSON.parse(body);
request('http://localhost:3000/api/2nd', function (err, resp2, body) {
context.second = JSON.parse(body);
request('http://localhost:3000/api/3rd', function (err, resp3, body) {
context.third = JSON.parse(body);
res.render('../views/project', context);
});
});
});
};
Simplest way if you use bluebird promise library:
var Promise = require('bluebird');
var request = Promise.promisify(require('request'));
module.exports = function (req, res) {
var id = req.params.id;
var urls = [
'http://localhost:3000/api/1st/' + id,
'http://localhost:3000/api/2st/' + id,
'http://localhost:3000/api/3st/' + id
];
var allRequests = urls.map(function(url) { return request(url); });
Promise.settle(allRequests)
.map(JSON.parse)
.spread(function(json1, json2, json3) {
res.render('../views/project', { json1: json1 , json2: json2, json3: json3 });
});
});
it executes all requests even if one (or more) fails
Related
Feel like I'm missing something here on how callbacks / async code is working.
places is undefined.
module.exports = (app) => {
app.get('/searchresults', (req, res) => {
var places = getGooglePlaces();
res.render('searchresults', {places: places});
});
};
function getGooglePlaces(){
var gp = require('googleplaces');
var config = require("../config.js");
var googlePlaces = new gp(config.apiKey, config.outputFormat);
var parameters = {
query: "restaurants in la"
};
var places = googlePlaces.textSearch(parameters, function (error, response) {
return(response);
});
};
You should use Promise to be able to get a result from a callback:
function getGooglePlaces(){
return new Promise((resolve, reject) => {
var gp = require('googleplaces');
var config = require("../config.js");
var googlePlaces = new gp(config.apiKey, config.outputFormat);
var parameters = {
query: "restaurants in la"
};
var places = googlePlaces.textSearch(parameters, function (error, response) {
if (error) {
reject(error);
}
resolve(response);
});
});
};
Then use then/catch to get a result:
app.get('/searchresults', (req, res) => {
getGooglePlaces()
.then(places => res.render('searchresults', {places: places}))
.catch(err => res.status(500).send('Error occured while searching Google Places');
});
I am trying to get result from function getWeather() in Nodejs to respone it to json in one router but I can not get it.
var request = require('request');
var publicIp = require('public-ip');
function getCity (userip){
var url = `https://ipinfo.io/${userip}/json`;
request(url, (err, respone, body)=>{
var data = JSON.parse(body);
var city = data['city'];
return getLocationKey(city);
})
}
function getLocationKey(city){
var url = `http://dataservice.accuweather.com/locations/v1/cities/search?q=${city}&apikey=${API_KEY}`;
request(url, (err, respone, body)=>{
var data = JSON.parse(body);
var key = data[0].Key;
return getWeather(key);
})
}
function getWeather(key){
var url = `http://dataservice.accuweather.com/forecasts/v1/daily/1day/${key}?apikey=${API_KEY}`;
request(url, (err, respone, body)=>{
var weather = JSON.parse(body);
console.log("weather: " + weather);
return weather;
})
}
I have got result from getCity() and getLocationKey(), but when get final result from getWeather() is not successfull.
I console.log weather is Object object. I try to sepate it and call it only, it respone for me weatherDetails as images
router.get('/weather-weather', (req, res)=>{
var city = 'hanoi';
var key = '353412'
var url = `http://dataservice.accuweather.com/forecasts/v1/daily/1day/${key}?apikey=${API_KEY}`;
request(url, (err, respone, body)=>{
var weatherDetails = JSON.parse(body);
res.json(weatherDetails);
})
})
However, I want to call it in this route to respone a json but it fail
router.get('/weather', (req, res)=>{
publicIp.v4()
.then(userip=>{
console.log("userIP: " + userip);
getCity(userip);
})
.catch(err=>{
console.log('Error: '+ err);
})
})
But it failed. I don't know how to return respone result from getWeather() function. How I can get it?
The function getXXX cannot get the "return" inside the callback function.
And you did not call res.json to send the result to the client.
You could pass res to getXXX and use it in this way:
function getCity(userip, res) {
var url = `https://ipinfo.io/${userip}/json`;
request(url, (err, respone, body) => {
var data = JSON.parse(body);
var city = data['city'];
return getLocationKey(city, res);
})
}
function getLocationKey(city, res) {
var url = `http://dataservice.accuweather.com/locations/v1/cities/search?q=${city}&apikey=${API_KEY}`;
request(url, (err, respone, body) => {
var data = JSON.parse(body);
var key = data[0].Key;
return getWeather(key, res);
})
}
function getWeather(key, res) {
var url = `http://dataservice.accuweather.com/forecasts/v1/daily/1day/${key}?apikey=${API_KEY}`;
request(url, (err, respone, body) => {
var weather = JSON.parse(body);
console.log("weather: " + weather);
res.json(weather);
})
}
router.get('/weather', (req, res) => {
publicIp.v4()
.then(userip => {
getCity(userip, res);
})
.catch(err => {
console.log('Error: ' + err);
})
})
I have the following module that basically performs a GET request to Google:
// my-module.js
var request = require('request');
var BPromise = require('bluebird');
module.exports = get;
function get() {
return BPromise.promisify(doRequest);
}
function doRequest(callback) {
request.get({
uri: "http://google.com",
}, function (err, res, body) {
if (!err && res.statusCode == 200) {
callback(null, body);
}
else {
callback(err, null);
}
});
}
And I want to use this module like so:
//use-module.js
var myModule = require('./my-module');
myModule().then(function (body) {
console.log(body);
});
The error I'm facing is the following:
myModule(...).then is not a function.
What am I doing wrong?
BPromise.promisify(doRequest) does not call doRequest, but returns a "promisified" version of that function. You should do that once, not at each call. This should work:
module.exports = BPromise.promisify(doRequest);
I am getting an undefined variable in my code and not sure what the error in my code is:
I get client as undefined when I call getClient...
I have a soap client creation singleton and I have:
var mySingleton = (function() {
var soap = require('soap');
var async = require('async');
var instance;
var client;
function init() {
var url = "http://172.31.19.39/MgmtServer.wsdl";
var endPoint = "https://172.31.19.39:9088";
var options = {};
options.endpoint = endPoint;
async.series([
function(callback) {
soap.createClient(url, options, function (err, result){
console.log('Client is ready');
client = result;
client.setSecurity(new soap.BasicAuthSecurity('admin-priv', 'password'));
callback();
});
}
],
function(err) {
if (err)
return next(err);
});
return {
getClient : function() {
console.log("I will give you the client");
**return client;**
},
publicProperty : "I am also public",
};
};
return {
getInstance : function() {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
module.exports = mySingleton;
so my consumer is :
var soapC = mySingleton.getInstance();
var mySoapClient = soapC.getClient();
I get mySingleton.client is undefined.
Why?
Sure there are better solutions than this one, but it shows you that it can be implemented easier (without async, without singleton):
var soap = require('soap');
var client;
var url = "http://172.31.19.39/MgmtServer.wsdl";
var options = {
endpoint: "https://172.31.19.39:9088"
};
module.exports = {
getClient: function (callback) {
if (client) {
callback(null, client);
return;
}
soap.createClient(url, options, function (err, result) {
if (err) {
callback(err);
return;
}
console.log('Client is ready');
client = result;
client.setSecurity(new soap.BasicAuthSecurity('admin-priv', 'password'));
callback(null, client);
});
},
publicProperty: "I am also public"
};
And when using the client:
// using the client
var mySoapServer = require('./path/to/above/code.js');
mySoapServer.getClient(function (err, client) {
if (err) { /* to error handling and return */ }
client.someRequestMethod(myEnvelope, function (err, response) {
// ...
});
});
There might be a problem when your Soap-Clients gets into trouble (there is no logic to reconnect in case of error). For this you could have a look at the source code of Redis-Client, MySQL-Client, MongoDB-Client, ...
Edit
Some comments on the different aproaches:
The Singleton-pattern is not needed here. Node will execute this JS file only once and further requires get only a reference to the exports. There is no need to create an IIFE scope - the variables won't be visible outside, only the exports.
Programming in Node.js is (besides some special cases) an all-async way. If not done consequently, it just doesn't work or fails/succeeds only if you have good/bad luck.
Error handling looks very much like a lot of boilerplate, but it's necessary in most cases.
I'm trying to bulk upload attachments to CouchDB using node.js and nano.
First, the walk module is used to find all files in upload folder and create array from them.
Next, each file from the array is supposed to be inserted into CouchDB via pipe and nano module.
However, the final result is that only one attachment has been uploaded.
var nano = require('nano')('http://localhost:5984')
var alice = nano.use('alice');
var fs = require('fs');
var walk = require('walk');
var files = [];
// Walker options
var walker = walk.walk('./uploads', {
followLinks: false
});
// find all files and add to array
walker.on('file', function (root, stat, next) {
files.push(root + '/' + stat.name);
next();
});
walker.on('end', function () {
// files array ["./uploads/2.jpg","./uploads/3.jpg","./uploads/1.jpg"]
files.forEach(function (file) {
//extract file name
fname = file.split("/")[2]
alice.get('rabbit', {revs_info: true}, function (err, body) {
fs.createReadStream(file).pipe(
alice.attachment.insert('rabbit', fname, null, 'image/jpeg', {
rev: body._rev
}, function (err, body) {
if (!err) console.log(body);
})
)
});
});
});
This is because you are mixing an asynchronous api with assumptions of this being synchronous.
After the first request you will get conflicts, cause the rabbit document has changed.
Can you confirm this using NANO_ENV=testing node yourapp.js?
I recommend using async if this is the problem
var nano = require('nano')('http://localhost:5984')
var alice = nano.use('alice');
var fs = require('fs');
var walk = require('walk');
var files = [];
// Walker options
var walker = walk.walk('./uploads', {
followLinks: false
});
walker.on('file', function (root, stat, next) {
files.push(root + '/' + stat.name);
next();
});
walker.on('end', function () {
series(files.shift());
});
function async(arg, callback) {
setTimeout(function () {callback(arg); }, 100);
}
function final() {console.log('Done');}
function series(item) {
if (item) {
async(item, function (result) {
fname = item.split("/")[2]
alice.get('rabbit', { revs_info: true }, function (err, body) {
if (!err) {
fs.createReadStream(item).pipe(
alice.attachment.insert('rabbit', fname, null, 'image/jpeg', {
rev: body._rev
}, function (err, body) {
if (!err) console.log(body);
})
)
}
});
return series(files.shift());
});
}
else {
return final();
}
}