How to block after http request with Node.js - javascript

I have the following code:
var options1 = {
host: 'maps.googleapis.com',
port: 80,
path: "/maps/api/geocode/json?latlng=" + lat + "," + lng + "&sensor=false",
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
var body1 = "";
var req = http.request(options1, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
//console.log('BODY: ' + chunk);
body1 += chunk;
});
res.on('close', function () {
console.log('get_zillow : ' + body1);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
req.end();
console.log('get_zillow : ' + body1);
I need to populate body1 with the result of the JSON response. However, the first console.log('get_zillow : ' + body1); never gets called -- for some reason the result never closes -- and the second console.log('get_zillow : ' + body1); prints nothing, since it is asynchronous and gets called before body1 gets populated.
Additionally, I need to make similar requests to different external sites several times in succession, with each request dependent on the json from the previous result. Is there any way to do this without writing three messy inner callbacks, and somehow block after an http request?

Change
res.on('close', function () {
console.log('get_zillow : ' + body1);
});
to
res.on('end', function () {
callback_function(body1);
});
//defined new function
function callback_function(finaldata)
{
// handle your final data
}

Related

Node JS Fetching JSON from url is executing AFTER the rest of the code

I wanted to get a JSON from a URL in my node JS code. The code is working fine, but the sequence of the execution is messed up because of the Async nature of the execution.
var http = require("https");
var number = 37302;
// these functions need to execute is sequence.
console.log('Before API Call');
var response = fetchJson(number);
console.log(response);
console.log('After API Call');
function fetchJson(number)
{
var url = 'https://example.com/api/getactionitems/' + number;
http.get(url, function(res){
var body = '';
res.on('data', function(chunk){
body += chunk;
console.log('JSON Retrieved.');
});
res.on('end', function(){
console.log('Parsing JSON');
var APIResponse = JSON.parse(body);
var Name = APIResponse.EmpName;
var outstring = APIResponse.ActionItem;
return ('Hi ' + Name + ', Your action Items are: '+ outstring);
});
})
.on('error', function(e){
return ("Got an error while fetching data.");
});
}
When this code executes, the sequence of the output strings are as follows:
Before API Call
undefined
After API Call
JSON Retrieved.
Parsing JSON
How can I correct the execution order, so that the sequence are like the following:
Before API Call
JSON Retrieved.
Parsing JSON
<Outpt from the JSON parsing>
After API Call
var http = require("https");
var number = 37302;
// these functions need to execute is sequence.
console.log('Before API Call');
fetchJson(number).then(function(res){
console.log(res);
console.log('After API Call');
}).catch(function(e){console.log('err',e)});
function fetchJson(number)
{
return new Promise(function(resolve,reject){
var url = 'https://example.com/api/getactionitems/' + number;
http.get(url, function(res){
var body = '';
res.on('data', function(chunk){
body += chunk;
console.log('JSON Retrieved.');
});
res.on('end', function(){
console.log('Parsing JSON');
var APIResponse = JSON.parse(body);
var Name = APIResponse.EmpName;
var outstring = APIResponse.ActionItem;
resolve('Hi ' + Name + ', Your action Items are: '+ outstring);
});
})
.on('error', function(e){
reject("Got an error while fetching data.");
});
});
}

Jasmine + Async functions

Here is my code:
'use strict';
var unitID = 0;
var getById = function(generalOptions, specificOptions) {
describe('API tests for: ' + specificOptions.name, function() {
var url = generalOptions.baseUrl + specificOptions.route;
// GET all items
it('= = = GET ALL test for ' + specificOptions.name + ' return status
code 200', function(done) {
generalOptions.request.get({
url: url
}, function(error, response, body) {
expect(response.statusCode).toBe(200);
expect(JSON.parse(body)).not.toBeFalsy();
if (specificOptions.route == '/devices/') {
var bodyJS = JSON.parse(body);
unitID = bodyJS.devices[0].id;
} else {
unitID = '';
}
console.log('Result 1 - ' + unitID);
done();
});
});
//GET by ID
it('= = = GET by ID test for ' + specificOptions.name + ' return status code 200', function(done) {
console.log('Result 2 - ' + unitID);
generalOptions.request.get({
url: url + unitID
}, function(error, response, body) {
expect(response.statusCode).toBe(200);
expect(JSON.parse(body)).not.toBeFalsy();
done();
});
});
})
};
module.exports = getById;
I need to wait, while unitID will be updated with first GET request and then use in in the next request.
The problem is, that it works asynchronously and unitID in the second request stay 0.
Can show how to implement solution with async/await or Promises?
Thanks!
For debugging reason I do console.log. For now it print:
Result 2 - 0
Result 1 - 59dffdgfdgfg45545g
You should not write test in such fashion where output of one test goes into other.Each "it" should be independent.
Instead you should make call twice(nested call) to achieve the value of unitID or ideally you should mock the service to return the data that is expected by the "it".

Node.js http.request Results Back as Variable

All,
I am trying to figure out how to pass the results from an https.request in node.js code out to a variable. I have an https.request setup that correctly passes the correct information to a SOAP API and gets the correct response back. My ultimate goal is to get the output from the https.request into a variable that I can call using Express.
Here is are my code chunks.
HTML:
<div class="row">
<div class="col-md-12" class="pull-left">
<p> TEST </p>
<p>{{soapreply}}</p>
</div>
JS:
app.post('/cucmmapper/submit', function (req, res) {
// FORM - DATA COLLECTION
var cucmpub = req.body.cucmpub;
var cucmversion = req.body.cucmversion;
var username = req.body.username;
var password = req.body.password;
var authentication = username + ":" + password;
var soapreplyx = '';
// SOAP - BUILD CALL
var https = require("https");
var headers = {
'SoapAction': 'CUCM:DB ver=' + cucmversion + ' listCss',
'Authorization': 'Basic ' + new Buffer(authentication).toString('base64'),
'Content-Type': 'text/xml; charset=utf-8'
};
// SOAP - AXL CALL
var soapBody = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
'<soapenv:Header/>' +
'<soapenv:Body>' +
'<ns:listCss sequence="?">' +
'<searchCriteria>' +
'<name>%</name>' +
'</searchCriteria>' +
'<returnedTags uuid="?">' +
'<name>?</name>' +
'<description>?</description>' +
'<clause>?</clause>' +
'</returnedTags>' +
'</ns:listCss>' +
'</soapenv:Body>' +
'</soapenv:Envelope>');
// SOAP - OPTIONS
var options = {
host: cucmpub, // IP ADDRESS OF CUCM PUBLISHER
port: 8443, // DEFAULT CISCO SSL PORT
path: '/axl/', // AXL URL
method: 'POST', // AXL REQUIREMENT OF POST
headers: headers, // HEADER VAR
rejectUnauthorized: false // REQUIRED TO ACCEPT SELF-SIGNED CERTS
};
// SOAP - Doesn't seem to need this line, but it might be useful anyway for pooling?
options.agent = new https.Agent(options);
// SOAP - OPEN SESSION
var req = https.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (d) {
soapreplyx = d;
console.log("Got Data: " + d);
});
});
// SOAP - SEND AXL CALL
req.write(soapBody);
res.render('cucmmapper-results.html'), {
'title': 'CUCM 2.1',
'soapreply': soapreplyx
};
req.end();
req.on('error', function (e) {
console.error(e);
});
});
}
The line "console.log("Got Data: " + d)" is getting the correct expected reply from the API, however, I can't figure out how to get that data into my variable "soapreplyx" which changes in Express to "soapreply".
Much appreciated for any help you might have!
You're not waiting for your request to respond before you call res.render(), so the value of soapreplyx is always '', its initial value. To correct this, add an 'end' event listener on the response object passed to your https.request() callback.
You're not appending the chunks of the response to your soapreplyx variable, you're reassigning its value with each successive chunk.
let soapRequest = https.request(options, soapResponse => {
soapResponse.on('data', chunk => {
soapreplyx += chunk
})
soapResponse.on('end', () => {
return res.render('cucmmapper-results.html', {
title: 'CUCM 2.1',
soapreply: soapreplyx
})
})
})
soapRequest.write(soapBody)
soapRequest.end()

Measuring time on node.js http requests

I was wondering if we can measure the time it takes for an http request to be completed using node.js. Modifying slightly an example from the documentation (here), one can easily write down the following code.
var http = require('http');
var stamp1 = new Date();
var stamp2, stamp3, stamp4;
var options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST'
};
var req = http.request(options, function(res) {
stamp3 = new Date();
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
res.on('end', function () {
stamp4 = new Date();
console.log ("Stamp 3: " + stamp3);
console.log ("Stamp 4: " + stamp4);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
stamp2 = new Date();
console.log ("Stamp 1: " + stamp1);
console.log ("Stamp 2: " + stamp2);
Now let me come to my point. On the response one can easily measure the time it takes for the response, since in the beginning stamp3 is set and on end stamp 4 is set. So, in principle for relatively large amounts of data these two timestamps will be different.
However, the question that I have is whether stamps 1 and 2 actually measure what is happening when the request is being prepared and dispatched. In other words, is req.write(....) a synchronous operation? Based on node.js principles I would expect req.write(...) to be an asynchronous operation where one can pass an arbitrarily large document and then upon successful completion we can have a callback knowing that the request has finished.
Comments?
Two function already exist for that:
console.time(id), start the timer
console.timeEnd(id) end the timer, print id followed by the time in ms
So in your case:
var req = http.request(options, function(res) {
console.time('Requete: '); //Begin to count the time
stamp3 = new Date();
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
res.on('end', function () {
stamp4 = new Date();
console.log ("Stamp 3: " + stamp3);
console.log ("Stamp 4: " + stamp4);
console.timeEnd('Requete: '); //Will print "Requete: X" with X being the time in ms
});
});
The docs mention no callback, so I'm assuming req.write as well as res.end to be synchronous.
So in your case if you're referring to just that one request that you're initializing, I think the time measurement should be accurate. I don't expect the time difference to be very big though (perhaps even in the same milisecond).

Uploading multipart form in pure nodejs

I have tried a bit of code to upload a file on node based server and i'm getting a socket hang up error.
After googling about the error I came across a post which suggested that request.end() if not called causes this error but as you will see code below I do have called request.end().
Any help,suggestion are appreciated
var http = require('http');
var fs = require('fs');
var options = {
hostname: 'api.built.io',
port : 443,
path : '/vi/uploads',
method : 'POST'
};
var request = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
var size;
fs.stat('/home/abhijeet/Downloads/fgo-2.jpg',function(err,stats){
size = stats.size;
console.log(size);
});
var boundaryKey = Math.random().toString(16); // random string
request.setHeader('Content-Type', 'multipart/form-data; boundary="'+boundaryKey+'"');
request.setHeader('application_api_key','1234');
request.setHeader('authtoken','123');
request.setHeader('Content-Length','42215');
// the header for the one and only part (need to use CRLF here)
request.write(
'--' + boundaryKey + '\r\n'
// use your file's mime type here, if known
+ 'Content-Type: image/jpeg\r\n'
// "name" is the name of the form field
// "filename" is the name of the original file
+ 'Content-Disposition: form-data; name="upload[upload]"; filename="/home/abhijeet/Downloads/fgo-2.jpg"\r\n'
+ 'Content-Transfer-Encoding: binary\r\n\r\n'
);
var readFile = fs.createReadStream('/home/abhijeet/Downloads/fgo-2.jpg', { bufferSize: 4 * 1024 })
.on('end', function() {
request.end('\r\n--' + boundaryKey + '--'); // mark the end of the one and only part
})
.pipe(request, { end: false }) // set "end" to false in the options so .end() isn't called on the request
request.on('error',function(error){
console.log(error);
});
// maybe write directly to the socket here?
request.end();
// console.log(readFile);

Categories