I'm fumbling my way through node.js with massive help from people on here and I'm struggling getting the body of a GET request into a variable.
Here's the code so far:
var speechOutput;
var myCallback = function(data) {
console.log('got data: '+data);
speechOutput = data;
};
var usingItNow = function(callback) {
var http = require('http');
var url = 'http://services.groupkt.com/country/get/iso2code/IN';
var req = http.get(url, (res) => {
var body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
var result = JSON.parse(body);
callback(result);
});
}).on('error', function(e){
console.log("Got an error: ", e);
});
};
usingItNow(myCallback);
I'm using examples from other posts to try and get the body of the GET request into the speechOutput variable but it is coming out as undefined.
Ultimately I want the RestResponse.result.name in speechOutput, but I thought I would take this one step at a time. Can anyone offer any pointers?
Further to this, I have tried the following, which still came back undefined - maybe there is a bigger issue with the code? It doesn't even seem to be getting to the parse.
res.on("end", () => {
// var result = JSON.parse(body);
callback('result');
});
putting the line callback('result'); before the line var req = http.get(url, (res) => { returns 'result' but anything else is either undefined or causes an error.
Quoting Roy T. Fielding:
Server semantics for GET, however, are restricted such that a body,
if any, has no semantic meaning to the request. The requirements
on parsing are separate from the requirements on method semantics.
Don't use get request to send body parameters. Use post requests. If you want to send data within a get request, add them to the query string.
Read this for more info about bodies in get requests:
HTTP GET with request body
Update:
Try to log errors in the response, add this before you set up the listeners:
var body = "";
const { statusCode } = res;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// consume response data to free up memory
res.resume();
return;
}
res.on("data", (chunk) => {
body += chunk;
});
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have created a nodejs express application using Express Generator.
In its route index.js I'm trying to make a rest api call using default HTTP module in the standard library https://nodejs.org/api/http.html#http_http_get_options_callback (I do not want to install external dependencies)and that would provide the values for title and welcome text in the view. Below is the code for index.js.
var express = require('express');
var router = express.Router();
const http = require('http');
/* GET home page. */
router.get('/', function(req, res, next) {
let titletext = '';
let wtext = '';
http.get('http://localhost:5000/api/values', (apires) => {
const { statusCode } = apires;
const contentType = apires.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// Consume response data to free up memory
apires.resume();
return;
}
apires.setEncoding('utf8');
let rawData = '';
apires.on('data', (chunk) => { rawData += chunk; });
apires.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
titletext=parsedData[1];
wtext=parsedData[0];
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
res.render('index', { title: titletext, data:wtext });
});
module.exports = router;
But it does not seem to be working and titletext and wtest were coming as empty strings. So, I added three breakpoints. One just after the get call, second after get call response comes and the last on the page response render call(res.render) at the very end.
Now when I run, I find that the get call breakpoint gets called,then the page response render call breakpoint gets called and finally the get call response breakpoint gets called, the data comes from the rest api but by then the page render call is already over and so the data from api call does not reach the view.
Any ideas how to solve this is sincerely appreciated
Http request call is async, so if you put res.render at the end of GET handler, it will render empty data before request returns response.
Following the document, you should parse response's body and render page from end event handler, like:
router.get('/', function(req, res, next) {
let titletext = '';
let wtext = '';
http.get('http://localhost:5000/api/values', (apires) => {
const { statusCode } = apires;
const contentType = apires.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// Consume response data to free up memory
apires.resume();
return;
}
apires.setEncoding('utf8');
let rawData = '';
apires.on('data', (chunk) => { rawData += chunk; });
apires.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
titletext=parsedData[1];
wtext=parsedData[0];
// Render page here
res.render('index', { title: titletext, data:wtext });
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
// Not here
});
I'm trying to find if there is a way to simulate a visit in a website like I was in web browser, with javascript execution etc...
If I try like with jsdom, google analytics shows me nothing for my personnel website. It's only capture source code.
How can I do that with node.js ?
What do you mean by simulate? When a web browser visits a website, it makes an http request to the server, and if the server returns an html document, it parses and shows it to you. You could do an http request using Node.js http module (example taken directly from docs):
http.get('http://nodejs.org/dist/index.json', (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type'];
let error;
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('Invalid content-type.\n' +
`Expected application/json but received ${contentType}`);
}
if (error) {
console.error(error.message);
// Consume response data to free up memory
res.resume();
return;
}
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
I write API in order to client upload file. API has content-type multiple/form-data. But I don't know get values from client send to my
router.post('/upload/file', async (req, res) => {
var body = "";
try {
req.on('data', function (chunk) {
body += chunk;
});
req.on('end', function () {
console.log('body: ' + body);
var formData = new FormData(body);
console.log("=====================", formData.entries);
// var {accessTok, type, file} = req.params;
//
// if (!accessTok || !type || !file) {
res.json({
code: -1000,
message: 'Missing parameter(s). Please provide accessToken, type upload, file upload.'
});
res.end();
return null;
})
// }
}catch(err){
res.json({err: err.message});
res.end();
return;
}
I tried use FormData but not done. I get error is not function, formData.getKey('') is them same.
I have a RESTish api on a node js server. When it receives a GET request, it is to call a function that will then be calling another server get function. The code looks like this:
var server = http.createServer(function(request, response) {
console.log("YEAHHH! ", request.method);
var string='';
// Inside a request handler method
if (request.method == "OPTIONS") {
console.log("options");
// Add headers to response and send
//response.writeHead(statusCode, responseHeaders);
response.writeHead(success,responseHeaders);
response.end();
}
if(request.method == "GET") {
string = soso();
}
console.log("*******", string);
response.writeHead(success,responseHeaders);
response.end(string);
});
soso() is the call to the other server. The issue is I want to send the response of the soso() function before its finished so all I'm getting is an empty string.
How do I get around this?
I'm sure this is a duplicate but can't quite find what I'm looking for. So, any help is appreciated.
EDIT
Code for the soso function:
var soso = function () {
console.log("this is being called");
var options = {...}
var req = https.get( options, function(res) {
var str = '';
res.on('data', function ( chunk ) {
str += chunk;
})
res.on('end', function () {
console.log ( "str is: ", str );
string = str;
})
req.end();
console.log(res.statusCode);
console.log(responseHeaders);
});
}
You can try something like this , I am not sure. I have not tested this. Pass the response object in soso function, then use response.end(string); after get request gets end.
var server = http.createServer(function(request, response) {
console.log("YEAHHH! ", request.method);
var string='';
// Inside a request handler method
if (request.method == "OPTIONS") {
console.log("options");
// Add headers to response and send
//response.writeHead(statusCode, responseHeaders);
response.writeHead(success,responseHeaders);
response.end();
}
if(request.method == "GET") {
string = soso(response); //send response object as argument
} else {
console.log("*******", string);
response.writeHead(success,responseHeaders);
response.end(string);
}
});
soso function
var soso = fuction(response){ // we pass the response object in soso function
console.log("this is being called");
var options = {...}
var req = https.get( options, function(res) {
var str = '';
res.on('data', function ( chunk ) {
str += chunk;
})
res.on('end', function () {
console.log ( "str is: ", str );
string = str;
})
req.end();
response.writeHead(success,responseHeaders);
response.end(string);
console.log(res.statusCode);
console.log(responseHeaders);
});
}
Whats the best way to read a remote file? I want to get the whole file (not chunks).
I started with the following example
var get = http.get(options).on('response', function (response) {
response.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
I want to parse the file as csv, however for this I need the whole file rather than chunked data.
I'd use request for this:
request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
Or if you don't need to save to a file first, and you just need to read the CSV into memory, you can do the following:
var request = require('request');
request.get('http://www.whatever.com/my.csv', function (error, response, body) {
if (!error && response.statusCode == 200) {
var csv = body;
// Continue with your processing here.
}
});
etc.
You can do something like this, without using any external libraries.
const fs = require("fs");
const https = require("https");
const file = fs.createWriteStream("data.txt");
https.get("https://www.w3.org/TR/PNG/iso_8859-1.txt", response => {
var stream = response.pipe(file);
stream.on("finish", function() {
console.log("done");
});
});
http.get(options).on('response', function (response) {
var body = '';
var i = 0;
response.on('data', function (chunk) {
i++;
body += chunk;
console.log('BODY Part: ' + i);
});
response.on('end', function () {
console.log(body);
console.log('Finished');
});
});
Changes to this, which works. Any comments?
function(url,callback){
request(url).on('data',(data) => {
try{
var json = JSON.parse(data);
}
catch(error){
callback("");
}
callback(json);
})
}
You can also use this. This is to async flow. The error comes when the response is not a JSON. Also in 404 status code .