using Node.js' https.request() and outputting to a browser - javascript

Im following a article about http requests to nasa's pic of the day. I'm trying to display the JSON object in browser from my server. But all Node.js' examples outputs the api results to a server's console. is it possible to have my server save/forward the response to the browser? I'd like to understand the native http module before relying on any dependencies. Also I'm not sure if it makes a difference but I'm using express to create my server. anything will help even a high level explanation because I'm so confused.
const https = require('https');
app.get('/', (req, res) => {
var url = 'https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY';
var nasa_obj
var request = https.get(url, function (resp) {
var body = '';
resp.on('data', function (chunk) {
body += chunk;
});
resp.on('end', function () {
nasa_obj = JSON.parse(body);
console.log("Got a response: ", nasa_obj);
res.send(nasa_obj)
});
}).on('error', function (e) {
console.log("Got an error: ", e);
});
request.end()
})
UPDATED: CODE IS CORRECT

You only want to send the response once it has been returned to you:
const https = require('https');
app.get('/', (req, res, next) => {
var url = 'https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY';
var nasa_obj
var request = https.get(url, function (response) {
var body = '';
response.on('data', function (chunk) {
body += chunk;
});
response.on('end', function () {
console.log("Got a response: ", body);
res.send(body);
});
}).on('error', function (e) {
console.log("Got an error: ", e);
next(e); // Pass error to error handling middleware
});
request.end()
})
Also make sure you are properly handling errors. Either send back a response to the browser to, as the code above is doing, pass it on to error handling middleware.

Related

My JSON.parse in app.js doesnt function properly

app.js:
const express = require("express");
const https = require("https");
const app = express();
const port = 3000;
app.get("/",function(req,res){
const url ="https://maps.googleapis.com/maps/api/geocode/jsonaddress=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY;
console.log(response.statusCode);
response.on("data",function(data){
var jatin=JSON.parse(data);
console.log(jatin);
})
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Error on Console
app.listen(3000,function(){ console.log("server started on port
3000"); })
server started on port 3000 200 undefined:26
"long_name"
SyntaxError: Unexpected end of JSON input
at JSON.parse ()
at IncomingMessage. (/home/jatin/Downloads/full_stack/Web-Development/maps/app.js:11:21)
at IncomingMessage.emit (events.js:189:13)
at IncomingMessage.Readable.read (_stream_readable.js:487:10)
at flow (_stream_readable.js:931:34)
at resume_ (_stream_readable.js:912:3)
at process._tickCallback (internal/process/next_tick.js:63:19) [nodemon] app crashed - waiting for file changes before starting
The output is visible when I run it on browser but on the console it throws an error.
For some reason JSON.parse() isn't working as expected.
I am trying to make a geocoding API call and in response, it gives me a JSON output...
which when I enter it as a URL on the browser the expected output is received
But when app.js is run on a node express server and when I hit my localhost:3000 I am getting the console error
Apparently the JSON.parse("data") is working but stops unexpectedly. Which leads to error.
You need to have your code to perform JSON.parse on end event instead, like this example form the documentation:
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}`);
});
Notice that this is http.get, but it should be the same for https.get, so in your code the on('data') should be used to assemble the chunks before your perform JSON.parse() on it.
const express = require("express");
const https = require("https");
const app = express();
const port = 3000;
app.get("/", function(req, res) {
const url = "API_URL";
https.get(url, function(response) {
console.log(response.statusCode);
let body = "";
response.on("data", function(data) {
body += data;
});
response.on("end", function() {
console.log(JSON.parse(body));
});
});
res.end("End data response");
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
basically .on('end', callback') and .on('data', callback') are event listener to data receive and request end events, and to be able to handle your requests response in node when using http(s).get you have to attache an event listener on data event which is invoked every time your request receives a chunk of the request response, and once the request ended by the service the event end will be invoked stating that there is no more data from the server requested hence the request ended.
as stated in the documentation:
The callback must take care to consume the response data for reasons
stated in http.ClientRequest section.

Can't nest HTTP GET inside another with node.js

I want to do a very simple task, yet I am stuck!
The scenario is like this:
After a get request to my api, I want to http.get from some external site, and then send back the response from this external site to the original api request.
Obviously, the calls are asychronous so the string loremParagraph, doesn't load correctly before sending it back to the api.
Also I get the error: Error: Can't set headers after they are sent.
Here is my code:
module.exports = function(app, express) {
var myLoremRouter = express.Router();
var loremParagraph = '';
//HTTP GET accessed at localhost:8081/mylorem
myLoremRouter.get('/', function(req, res) {
// Fetch one paragpraphlorem ipsum text from http://www.faux-texte.com/text-random-1.htm
http.get("http://www.faux-texte.com/text-random-1.html", function(resp) {
resp.on('data', function(chunk) {
// console.log('BODY: ' + chunk);
var $ = cheerio.load(chunk);
loremParagraph = $('div.Texte').text();
console.log(loremParagraph);
// console.log(resp.status);
});
})
// If any error has occured, log error to console
.on('error', function(e) {
console.log("Got error: " + e.message);
});
//Finally send the result back to the api call
res.json({ message: loremParagraph });
});
return myLoremRouter;
};
Try this. Here chunks are added till we are ready to use the complete data.
https://stackoverflow.com/a/21953201/6219247
myLoremRouter.get('/', function(req, res) {
var body = '';
http.get({
host: 'www.faux-texte.com',
port: 80,
path: '/text-random-1.html'
}, function(resp) {
resp.on('data', function(chunk) {
body += chunk;
});
resp.on('end', function(chunk) {
var $ = cheerio.load(body);
loremParagraph = $('div.Texte').text();
res.json({ message: loremParagraph });
});
})
.on('error', function(e) {
// handle/send error
res.send(/*...*/);
});
});

Node js response.write(average size html) takes forever for page to load

This is a simple web scraper.
The HTTP request is sent by NodeJS and response to the client with HTML. The console show body.toString() immediately, but on the browser it loads forever, when I stop the server, it display the page.
I did the similar things in express, it just works, but for some reason, I am not allowed to use express. So I have to write in pure NodeJS.
I have also tried to do it without HTTP request, only left the function response.write and response.end in the if statement, it is fine when I put a few strings in response.write, but when I put minify HTML inside response.write, same situation happen, loading takes forever and display the page when I stop the server.
The following is my code, any help is appreciated, thanks in advance.
const url = require("url"),
http = require('http');
const port = 3000;
const requestHandler = (request, response) => {
if (request.url === "/") {
const options = {
"method": "GET",
"hostname": "something.com",
"port": null,
"path": "/",
"headers": {
"content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
}
};
const req = http.request(options, function (res) {
let chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
let body = Buffer.concat(chunks);
console.log(body.toString());
const html = body.toString();
response.write(html);
response.end();
});
});
req.write("");
req.end();
}
}
const server = http.createServer(requestHandler)
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log(`server is listening on ${port}`)
})

Invalid response using https module in javaScript to fetch a public facebook profile

I am using node's https module to fetch my public profile from facebook. But i am getting 302 status code in response. Following is the code i am using:
var https = require('https');
var options = {
hostname: 'www.facebook.com',
path: '/suri.nik',
method: 'GET'
};
var results = '';
var req = https.request(options, function (res) {
console.log('STATUS CODE : ' + res.statusCode);
res.on('data', function (chunk) {
results = results + chunk;
});
res.on('end', function () {
console.log(results);
});
res.on('error', function () {
console.log('error here');
});
});
req.on('error', function (e) {
console.log('error in ur request: ' + e);
});
req.end();
I am getting STATUS CODE : 302, i should be getting status code : 200 with valid html in response of my profile. I am able to fetch the public profile from my browser or postman using the same link(www.facebook.com/suri.nik) Where lies the issue? is it the way i am making my request?

Node.js TypeError: Cannot call method 'write' of undefined

This is the code in nodejs for to call the openweather API and print the result on the 127.0.0.7:8124 but do not understand why it does not work
var http = require('http');
function getData(city, res){
var urlData = 'http://api.openweathermap.org/data/2.5/weather?q='+city;
http.get(urlData, function(resi) {
var body = '';
resi.on('data', function(chunk) {
body += chunk;
});
resi.on('end', function() {
var dataResponse = JSON.parse(body)
res.write(dataResponse);
});
}).on('error', function(e) {
res.write("Got error: " + e);
});
}
// create http server
http.createServer(function (req, res) {
var query = require('url').parse(req.url).query;
var app = require('querystring').parse(query).city;
// content header
res.writeHead(200, {'Content-Type': 'text/plain'});
if(app){
console.log("ad: "+getData(app));
} else res.write("Use url:port?city=xxxx");
res.end();
}).listen(8124);
console.log('Server running at 8124');
this is the error
overflow#overflow-1015cx:~/Scrivania/nodeweather$ node app.js
Server running at 8124
ad: undefined
/home/overflow/Scrivania/nodeweather/app.js:15
res.write(dataResponse);
^
TypeError: Cannot call method 'write' of undefined
at IncomingMessage.<anonymous> (/home/overflow/Scrivania/nodeweather/app.js:15:13)
at IncomingMessage.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)
overflow#overflow-1015cx:~/Scrivania/nodeweather$
Why can not I return the result?
You are not passing the response object into getData
I believe it should look like this, but I have not tested it.
if(app){
console.log("ad: "+getData(app,res));
} else res.write("Use url:port?city=xxxx");\
If you read the error, its not telling you that you can't write, it's saying that you're trying to call write on a null object. If you trace the clues as to how res can be null, it should become clear.
Nodejs is async, res.end() is called before of res.write inside the http request.. so you need to use some "promise" tecnique or at least callbacks. However this code cannot work since you're trying to write a parsed json string, but the write method accepts only strings or buffer...moreover getData doesn't return nothing..so console.log("ad: "+getData(app,res,res.end)); prints an undefined variable.
maybe this code more fits your idea ( tested and working using "rome" ):
var http = require('http');
function getData(city, res,callback){
var urlData = 'http://api.openweathermap.org/data/2.5/weather?q='+city;
http.get(urlData, function(resi) {
var body = '';
resi.on('data', function(chunk) {
body += chunk;
});
resi.on('end', function() {
body=JSON.stringify(JSON.parse(body), null, 4)
res.write(body);
callback(body);
});
}).on('error', function(e) {
res.write("Got error: " + e);
callback("error");
});
}
// create http server
http.createServer(function (req, res) {
var query = require('url').parse(req.url).query;
var app = require('querystring').parse(query).city;
// content header
res.writeHead(200, {'Content-Type': 'text/plain'});
if(app){
getData(app,res,function (message) {
console.log("ad:",message);
res.end();
});
} else {
res.write("Use url:port?city=xxxx");
res.end("done");
}
}).listen(8124);
console.log('Server running at 8124');

Categories