Node.JS where to put the response.end() - javascript

I'm developing a simple NODE.JS application. First I create an httpServer using http module. Then I route the request to the requestsHandlers.js page. 'Response' parameter cames from the creation of the httpServer. Process1, process2 and process3 should write an answer to the page. This is the objective of this app, that process1, process2 and process3 write its respective text.
requestHandlers.js
var process1 = require("./process1");
var process2 = require("./process2");
var process3 = require("./process3");
function iniciar(response) {
console.log("Manipulador de peticiĆ³n 'iniciar' fue llamado.");
response.writeHead(200, {"Content-Type": "text/html"});
process1.fc1(response);
process2.fc2(response);
process3.fc3(response);
//response.end() //WHERE DO I PLACE IT?
}
As you can see, the response parameter is passed to process1.js, which after parsing some data shoud echo some information.
process1.js
var request = require('request')
function fc1 (response){
var url = 'http://webpagethatreturnsJSONfile.com/'
//Download webpage data and parses it
request(url, function(err, resp, body) {
if (err)
throw err;
var jsonResult = JSON.parse(body);
response.write("Number:" + jsonResult.number + '');
//response.end() //WHERE DO I PLACE IT?
});
}
exports.fc1 = fc1;
The point is that I don't know where to put 'response.end()'. Each process takes some time and I want to 'end' when all processes have echo their text.
How could I do it?
I don't know if the code I've attached is enough for helping me.

Related

JavaScript return not working as expected

This is a total newbie questions, and I'm trying to learn JavaScript and node.js. I'm attempting to use request to grab information from an api, and then store the information in an array that I can then manipulate.
Here is my code so far:
const request = require('request');
var url = "https://www.predictit.org/api/marketdata/ticker/CHINA.INAUGURAL.2017";
var info = request(url, function(err, res, body){
var json = JSON.parse(body);
return json;
})
However, the info variable seems to only store something that I think is related to the request call, but I'm not sure. If I replace return json with console.log(json) then it prints the array immediately, though I can't get it to store it.
I would like to tell node info['ID'] and have it return 2835
Node does not work like this. Node is asynchronous.
You can try this,
var info;
request(url, function(err, res, body){
info = JSON.parse(body);
});
Looks like you' re requesting xml file from that url. You can install xml2js library for nodejs by typing npm install xml2js and let it parse the xml for you. After that
var parseString = require('xml2js').parseString;
var url = "https://www.predictit.org/api/marketdata/tick /CHINA.INAUGURAL.2017";
var info = request(url, function(err, res, body){
parseString(body, function (err, result) {
info = JSON.parse(JSON.stringify(result));
});
return info;
})
I hope this one should work,
request('https://www.predictit.org/api/marketdata/ticker/CHINA.INAUGURAL.2017',
function (err, res) {
if (err) {
console.log('ERROR: Something went wrong');
}
else {
parseString(responce.body, function (err, result) {
res.json(result);
});
}
});
I think that data is stored into 'info' variable but you're using it before data is stored.
Here it takes some time for API call to process and get data. Then it will be stored into 'info' variable. Have a timeout of 5s and then try console.log(info[1]) and would return expected value.
This is due to asynchronous nature of nodejs. Here your code might be executing info[1] before it is set by API call.

Firebase Database updates slowly sometimes not at all

Good morning everyone, I have a question regarding the behavior of my firebase database.
I am populating an end point on my database user with multiple POST requests to my express server app.js from my client like so:
element.on("click", function(){
send request 1 - endpoint1
send request 2 - endpoint2
send request 3 - endpoint3
}
Then in my app.js I have handlers at the routes that use the Request package to make three seperate GET request to the Halo Waypoint API like so:
app.post(endpoint1, function(req,res){
request(HaloAPI + endpoint1, function(error, res, body){
[store data from the response body into an
object to be sent to firebase endpoint 'user']
// User's stats
database + "/user".set(dataObject)
}
}
app.post(endpoint2, function(req,res){
request(HaloAPI + endpoint2, function(error, res, body){
[store data from the response body into an
object to be sent to firebase endpoint 'user'.
This is a url for an image]
//This is a player's emblem
database + "/user/emblem".set(dataObject)
}
}
app.post(endpoint3, function(req,res){
request(HaloAPI + endpoint3, function(error, res, body){
[store data from the response body into an
object to be sent to firebase endpoint 'user'.
This is a url for an image]
//This is a player's Spartan portrait
database + "/user/spartanImage".set(dataObject)
}
}
I'm expecting the database to be updated all at the same time; however, that is not the case all the time. Usually when I click the button with the event listener attached endpoint 2 and 3 come in at the same time as the data from endpoint 1, but most of the time I only get data from only endpoint 2 or only endpoint 3. Eventually I stop getting the data from endpoint 2 and 3 all together. In fact, with this current setup I can see the endpoints user/emblem and user/spartanImage populate in the database console but then they are taken away as soon as they are added. This has been troubling me from the beginning of this project and I would really appreciate some insight from someone more experience in Firebase than myself. Below I will link my relevant code, thanks in advance for the help.
request.js is where the initial AJAX calls are made client-side:
$searchButton.on("click", function(event){
event.preventDefault();
// the value of the search field creates the request object
// it is just a user's Xbox Live Gamertag and is used for the
// the subsequent requests.
var $search = $("#searchField").val();
$.post(homeRoute + "statSearch", {search: $search}, function(data){
console.log(data)
});
firebase.database().ref().on("value", function(snapshot){
function ez(path){
return snapshot.child(path).val();
}
var dataObject = {
gamertag: ez("gamertag"),
totalKills: ez("totalKills"),
totalDeaths: ez("totalDeaths"),
totalGames: ez("totalGames")
};
console.log(dataObject)
});
$.post(homeRoute + "emblemSearch", {search: $search}, function(data){
console.log(data)
});
$.post(homeRoute + "spartanSearch", {search: $search}, function(data){
console.log(data)
});
From there we go over to app.js my express server to make GET requests to the Halo Waypoint API and send the response formatted with the data I want to firebase:
app.post("/statSearch", function(req, res){
var search = req.body.search;
var statsOptions = new Options("https://www.haloapi.com/stats/h5/servicerecords/warzone?players="+search);
request(statsOptions, function (error, response, body) {
if (error) throw new Error(error);
var body = JSON.parse(response.body)
var playerData = {
gamertag: body.Results[0].Id,
totalKills: body.Results[0].Result.WarzoneStat.TotalKills,
totalDeaths: body.Results[0].Result.WarzoneStat.TotalDeaths,
totalGames: body.Results[0].Result.WarzoneStat.TotalGamesCompleted
};
res.send(playerData)
var userRef = ref.child("user");
// sending off the data object to Firebase at the "user" endpoint
userRef.set(playerData);
});
});
//emblem
app.post("/emblemSearch", function(req, res){
var search = req.body.search;
var imgOptions = new Options('https://www.haloapi.com/profile/h5/profiles/'+search+'/emblem', '512');
request(imgOptions, function (error, response, body) {
if (error) throw new Error(error);
var imgString = response.request.uri.href;
res.send(imgString);
var emblemRef = ref.child("user/emblem");
// sending off the url to Firebase at the endpoint "user/emblem"
emblemRef.set(imgString);
});
});
//spartan image
app.post("/spartanSearch", function(req, res){
var search = req.body.search
var spartanOptions = new Options('https://www.haloapi.com/profile/h5/profiles/'+search+'/spartan', '256');
request(spartanOptions, function (error, response, body) {
if (error) throw new Error(error);
var imgString = response.request.uri.href;
res.send(imgString);
var spartanImage = ref.child("user/spartanImage");
// doing the same as emblem to this endpoint^^^^
spartanImage.set(imgString);
});
});

Http request document head

I need to get the document title.
so I try to send request, and paser the response html to get title.
example (via nodejs module request):
request.get("http://www.google.com", function(err, res, body) {
var title = body.match(/<title>(.*?)</title>/g)[1];
})
but when the document is particularly large. the request is slowly.
Is there a way to get document title quickly? Please suggest. Thanks.
Request can give you stream of decompressed data as it is received: http://github.com/request/request#examples (2nd example)
You could keep appending the data received in a buffer, and checking whether it has your desired content yet ("</title>"). As soon as you get it, you could get your title and ignore the rest of the buffer in the stream.
var request = require('request');
var buffer = '';
var flag = 0;
request({
method: 'GET',
uri: 'http://www.google.com',
gzip: true
}).on('data', function(data) {
if (buffer.indexOf('</title>') == -1)
buffer += data;
else done();
});
function done() {
if (flag) return;
flag++;
var title = buffer.match(/<title>(.*?)<\/title>/)[1];
console.log(title);
}

AJAX call with Express

I am trying to append HTML dynamically with Express framework in a static HTML file that my server serves. I've found about the cheerio module that does exactly what I want, but I was wondering if there is a much cheaper way for the system instead of loading the whole HTML and appending a string.
I searched about AJAX and how to communicate with the client but I didn't manage to make it work. The code I am using with cheerio is:
exports.modify = function(req, res){
var html = fs.readFileSync(__dirname + '/../public/index.html', 'utf8');
var $ = cheerio.load(html);
var scriptNode = '<p>Source code modified</p>';
$('body').append(scriptNode);
fs.writeFile(__dirname + '/../public/index.html', $.html(), function (err) {
if (err) throw err;
console.log('It\'s modified!');
});
res.send($.html());
};
How can I do it in more 'proper' way (maybe with AJAX call)? Any suggestions would be more than welcome.
Assuming you want to handle JSON as a data type then you can setup another specific route or you can filter the request type within the current route handler :
exports.index = function(req, res) {
var data = someData.fetch();
switch(req.format) {
case 'json':
res.json(data);
break;
default:
res.render('template', {
data:data
});
}
};

How to pass object parameters to functions in JavaScript

My server.js is
// server.js - the outer server loop
var http = require('http')
, php = require("./phpServer");
function start() {
function onRequest(request, response) {
php.phpServer('D:/websites/coachmaster.co.uk/htdocs',request, response);
response.write('Ending');
response.end();
}
http.createServer(onRequest).listen(80);
console.log("Server started.");
}
exports.start = start;
That calls php.phpServer every request with response as the 3rd param.
phpServer contains.
//
// phpServer.js - a generic server to serve static files and
//
var fs = require('fs')
, pathfuncs = require('path')
, url = require('url')
, mimetypes = require('./mimetypes')
function phpServer(root, request, response) {
// serve static or pass to php.
var data = url.parse(request.url);
var ext = pathfuncs.extname(data.pathname);
fs.stat(root+request.url, function(err, stat) {
if (err || !stat.isFile()) { // error or not file.
console.log('404');
response.writeHead(404);
response.write('Not Found');
return;
}
// exists - serve.
console.log("serve("+root+request.url+", mimetypes.mimetype("+ext+"))");
response.writeHead(200, {'Content-Type': mimetypes.mimetype(ext)});
response.write('Somethign to serve');
// fs.createReadStream(root+request.url).pipe(response);
});
}
exports.phpServer = phpServer
As I see it, response is an object and is passed by reference, therefore the response.write() here should write to the response.
It doesn't. Response here is NOT the same as response in onRequest, so nothing in phpServer is sent to the browser - not code nor content.
The console.logs come out and show what I would expect.
How can I get the object response passed so I can call write on it?
------------- added later -------------------
I've tried to apply answers given and code for server.is now
// server.js - the outer server loop
var http = require('http')
, fs = require('fs')
, pathfuncs = require('path')
, url = require('url')
, mimetypes = require('./mimetypes')
function phpServer(root, request, res) {
// code adapted from page 118 of Smashing Node.js by Guillermo Rauch
// res is response provided to onRequest.
var data = url.parse(request.url);
var ext = pathfuncs.extname(data.pathname);
res.write('Start reply');
fs.stat(root+request.url, function(err,stat) {
// define delayed callback - reponse in scope
if (err || !stat.isFile()) { // error or not file.
console.log('404');
res.writeHead(404);
res.write('Not Found');
res.end
return;
};
// exists so serve.
console.log("serve("+root+request.url+", mimetypes.mimetype("+ext+"))");
res.writeHead(200, {'Content-Type': mimetypes.mimetype(ext)});
res.write('The file contents');
res.end;
} // end callback,
); // end fs.stat call.
} // end phpServer
function start() {
function onRequest(request, response) {
phpServer('D:/websites/coachmaster.co.uk/htdocs',request, response);
}
http.createServer(onRequest).listen(80);
console.log("Server started.");
}
exports.start = start;
This does not reply at all - it times out. However the call to res.writeHead will either
fail, if res is out of scope/does not exist/undefined, or succeed if re is the param passed in.
It succeeds, and is followed by write and end, so please - what have I got wrong.
If the file does not exist I get a start reply and then a timeout.
At the res.write('Start reply'); res is the response param, yet it isn't later in the fs.stat call-back.
Why not?
Damn - this is frustrating.
The call to response.end should be moved from the onRequest function to phpServer. As it stands phpServer cannot write anything else since the stream has been closed.
function onRequest(request, response) {
php.phpServer('D:/websites/coachmaster.co.uk/htdocs',request, response);
// response.end(); // move this to phpServer
}
As explained in the documentation for response.end
This method signals to the server that all of the response headers and body have been sent; that server should consider this message complete.
Your problem is not with parameter passing, it's with basic asynchronous control flow. The stat() function does not do its work immediately. Its callback parameter is called when it's done. You basically cannot structure the code the way you've done it. Instead, your "phpServer" code will need to take a callback parameter of its own, and call it after it does its work.

Categories

Resources