I am a newbie to node and js and try to create a website in express that makes three Rest API calls before rendering the page. At the moment I have the below, which returns some json which I convert into a list of objects.
Some of these properties only return id values and I would like to run three more API requests that return lookups on these Id's so that I can present this data to the user as meaningful values.
I could do this synchronously by running the next API call where I am currently rendering the index page, but that looks really messy. All the async tutorials I have seen confuse the hell out of my newbie way of thinking though. Can someone post an easy to follow example for async that somewhat reflects the below structure?
var issues_json = "";
var request = http.request(options, function(response) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
response.on("data", function(data) {
issues_json += data;
});
response.on("end", function() {
console.log(issues_json);
var column_obj = JSON.parse(issues_json);
res.render('index', {
title: 'List of Issues',
response: issues_json,
objects: column_obj
});
});
response.on("error", function(e) {
console.log(e.Message);
res.render('index', {
title: 'error',
e: e.Message
});
});
});
request.end();
You should use Request
You would have something like
app.get("/route", function(req, res) {
var callbackThree = function(error, resp, body) {
var data = JSON.parse(body);
res.send({title; "My Title", data: data});
}
var callbackTwo = function(error, resp, body) {
request("api.com/42", callBackThree);
}
var callbackOne = function(error, resp, body) {
request("api.com/things", callBackTwo);
}
request("api.com/users", callBackOne);
}
check this out: https://github.com/JacksonTian/eventproxy. It's a js lib which makes async calls into events. The only difference from the ticked answer is its way of writing code.
Related
Am trying to design a REST api which will throw an aggregated response from multiple apis.
Following is the NodeJS code am trying to execute -
Pseudo Code start
//endpoint to be called from a browser / REST client
router.get('/api/v1/getItems', (req, response, next) => {
var result = {} // hold the aggregated response from multiple apis
//internally fire another endpoint & add the response over to the var result
http.get(endpoint 1, function(resp){
add response to result})
http.get(endpoint 2, function(resp){
add response to result
})
return response.json(result);
}
Pseudo Code end
// endpoint to be called from the browser or REST Client.
router.get('/api/v1/getItems', (req, response, next) => {
var results = {};
// Nested Endpoint 1
var optionsgetmsg = {
host : 'host.domain.com', // tthe domain name
port : 9043,
path : '/services/itemdata', // the rest of the url
method : 'GET' // do GET
};
//child endpoint
var reqGet = http.request(optionsgetmsg, function(res) {
res.on('data', function(d) {
console.log("d "+ d); // child response
results.itemdata = d;
return response.send(results);
//process.stdout.write(d);
});
res.on('end', function(d){
})
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
});
The result in the above case should be the output 'd'. The output 'd' is the response from the child endpoint.
Actual result am getting is an empty object. {}
If you are sending JSON, you must set the headers correctly and the response:
//child endpoint
var reqGet = http.request(optionsgetmsg, function(res) {
res.on('data', function(d) {
res.setHeader('Content-Type', 'application/json');
var results = d;
response.send(JSON.stringify(results));
});
It is unclear as to what exactly you are asking for.
I have a simple node Express app that has a service that makesa call to a node server. The node server makes a call to an AWS web service. The AWS simply lists any S3 buckets it's found and is an asynchronous call. The problem is I don't seem to be able to get the server code to "wait" for the AWS call to return with the JSON data and the function returns undefined.
I've read many, many articles on the web about this including promises, wait-for's etc. but I think I'm not understanding the way these work fully!
This is my first exposer to node and I would be grateful if somebody could point me in the right direction?
Here's some snippets of my code...apologies if it's a bit rough but I've chopped and changed things many times over!
Node Express;
var Httpreq = new XMLHttpRequest(); // a new request
Httpreq.open("GET","http://localhost:3000/listbuckets",false);
Httpreq.send(null);
console.log(Httpreq.responseText);
return Httpreq.responseText;
Node Server
app.get('/listbuckets', function (req, res) {
var bucketData = MyFunction(res,req);
console.log("bucketData: " + bucketData);
});
function MyFunction(res, req) {
var mydata;
var params = {};
res.send('Here are some more buckets!');
var request = s3.listBuckets();
// register a callback event handler
request.on('success', function(response) {
// log the successful data response
console.log(response.data);
mydata = response.data;
});
// send the request
request.
on('success', function(response) {
console.log("Success!");
}).
on('error', function(response) {
console.log("Error!");
}).
on('complete', function() {
console.log("Always!");
}).
send();
return mydata;
}
Use the latest Fetch API (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make HTTP calls. It has built-in support with Promise.
fetch('http://localhost:3000/listbuckets').then(response => {
// do something with the response here
}).catch(error => {
// Error :(
})
I eventually got this working with;
const request = require('request');
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
parseString(body, function (err, result) {
console.log(JSON.stringify(result));
});
// from within the callback, write data to response, essentially returning it.
res.send(body);
}
else {
// console.log(JSON.stringify(response));
}
})
I am trying to fetch a page from port 1717 but when my bandwidth is unavailable, the http.get on error callback logs errno ENOENT whereas when I turn my bandwidth back on, it logs errno ECONNRESET. Regardless of my computer being offline or not, the url http://localhost:1717/admin/available/ ALWAYS returns content in the browser as long as the server is up and running. I've tried using postman and I have also tried using request method of the http module instead of get. I ended request after using it but I still got the same errors.
Meanwhile I have tried getting other links besides those on localhost and it fetched them. In some other threads, I saw people suggest I use hostname 127.0.0.1 instead of localhost. That too did not work so I switched to the request module from npm then there was a slight difference in behavior. In the server.js, I have sommething like this for GET requests hitting /admin/available/
console.log('giving you table', table)
res.writeHead(200, {"Content-Type": "text/html"});
res.end(table);
However, when I use the request module, it throws the error ECONNRESET but in the CLI window where the server is running, this console.log('giving you table', table) is logged, meaning the server does see that request but somehow, the module still throws ECONNRESET and the body and response variables are undefined, claiming it cannot see it. What can I do about this?
I'll be posting my code below in case I'm missing something.
var http = require('http'),
component = require('../lib/render-component'),
render = {username: '', available: '', orders: '', frequent: ''};
// for simplicity
var request = require('request');
request('http://localhost:1717/admin/available', function(err, res, body) {
console.log(err, res, body)
});
// intended use scenario
http.get({port: 1717, path: '/admin/available/', headers: {Accept: 'text/html'}}, function(res) {
var temp = '';
res.setEncoding('utf8');
console.log('inside get');
res.on('data', function (chunk) {
temp += chunk;
}).on('end', function() {
render.available = temp;
http.get('http://localhost:1717/admin/order/?page=0', function(res) {
var temp = ''
res.setEncoding('utf8');
res.on('data', function (chunk) {
temp += chunk;
}).on('end', function() {
render.orders = temp;
ordersModel.find({status: 'delivered'}, 'food', function (err, orders) {
if (err) throw err;
var hashMap = [], returnArr = [];
orders.forEach(function (order) {
hashMap.push(order.toObject()['food'].split(","));
})
hashMap.reduce(function(a, b) {
return a.concat(b)
}, []).forEach(function(item) {
if ((k = returnArr.findIndex(function(elem) {
return elem[0] == item;
})) != -1) {
returnArr[k][1]++;
}
else returnArr.push([item, 1]);
})
// filter the ones with the highest value
hashMap = [], returnArr = returnArr.sort(function(a, b) {
return b[1] - a[1];
}).slice(0, 5).forEach(function(elem) {
hashMap.push({name: elem[0], counter: elem[1]})
});
render.frequent = component("frequent", hashMap);
console.log(render)
}) // orders model find
}); // get orders
}).on('error', function(e) {
console.log(e)
});
}); // available on end
}).on('error', function(e) {
console.log('err available', e)
}); // available on error
Please help me. I've been stuck for three days now.
I have some CRUD controllers set up in my project like this:
var getMaps = function (req, res) {
Map.find({}).exec(function (err, collections) {
res.send(collections);
});
};
In order to use these in the server side code, I've been using node's http.get like this:
var options = {
host: 'localhost',
port: 3030,
path: '/api/map'
};
http.get(options, function (res) {
var data = '';
res.on("data", function (chunk) {
data += chunk;
}).on('end', function () {
data = JSON.parse(data);
console.log(data);
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
});
where my routes file contains
app.get('/api/map', map.getMaps);
Is this the correct way of doing it? It seems like it would be slow since it is an http request but I don't know any other way to do it
Better you go through $http and $resource links once to have a better understanding of angular's APIs.
You can also try out the MEANs CRUD module which comes by default when you generate a MEAN application.
I am trying to process Wikipedia articles, and want to receive a list of all Wikipedia articles. In order to do this I am frequently sending http requests to the Wikipedia API, which allows you to receive 500 titles at time and also returns an apcontinue string, which, when used in the following request, returns title starting from that string.
In order to do this, I am using the agentkeepalive module:
var http = require('http');
var Agent = require('agentkeepalive');
var keepaliveAgent = new Agent({
keepAlive: true,
maxSockets: 5,
timeout: 5000,
keepAliveTimeout: 3000
});
To send an http request to Wikipedia, I use the following code:
function wikipediaApiCall(params, callback) {
var options = {
host: 'en.wikipedia.org',
path: '/w/api.php?' + createParamString(params),
method: 'GET',
agent: keepaliveAgent
};
var callbackFunc = function(response) {
var err;
var str = '';
if (('' + response.statusCode).match(/^5\d\d$/)) {
err = new Error('Server error');
}
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
});
response.on('error', function (e) {
err = new Error('Request error');
});
response.on('timeout', function () {
err = new Error('Timeout');
response.abort();
callback(err);
});
response.on('end', function () {
var obj = JSON.parse(str);
if (obj.warnings) {
err = new Error('Request error');
}
callback(err, obj);
});
}
var req = http.request(options, callbackFunc);
req.setTimeout(5000);
req.on('error', function(err) {
callback(err, null);
return;
});
req.on('timeout', function () {
err = new Error('Timeout');
response.abort();
callback(err);
});
req.on('finish', function(){
console.log('ended');
});
req.end();
}
However, after sending between 16 and 20 request, I am not getting any response, but my request also does not time out.
Any ideas why this is happening?
Update
The request I send to Wikipedia contains the following parameters:
var params = {
list: 'allpages',
aplimit: limit,
apfrom: from,
continue: cont,
// apfilterredir: 'nonredirects'
};
Interestingly, after leaving out the nonredirects setting, I was able to send and receive up to 330 requests, but no more than that.
Update 2
I was able to register a finished event. It appears to be fired for the request that is failing as well. I modified the code accordingly.
Perhaps you need a bot flag to have higher API limits. Maybe there are too many requests in parallel; WMF recommendation is to make requests serially in case of such big tasks. Also, you should use the maxlag parameter with low values, per WMF API Etiquette.