capture returned functions in javascript - javascript

I have the following piece of code as follows:
function(staticPath) {
console.log('static Path = ' +staticPath);
return function(data, response) {
console.log('data = ' +data);
console.log('response = ' +response);
var readStream;
// Fix so routes to /home and /home.html both work.
data = data.replace(/^(\/home)(.html)?$/i, '$1.html');
data = '.' + staticPath + data;
fs.stat(data, function(error, stats) {
if (error || stats.isDirectory()) {
return exports.send404(response);
}
readStream = fs.createReadStream(data);
return readStream.pipe(response);
});
}
}
This function basically parses the path to a HTML file and displays the contents of the file.
I am not able to understand how to call this method from outside.
I am calling it as follows:
staticFile("D:\\Node Applications\\public\\home.html")
I can capture it inside a variable innerFunc and i can call the inner function as innerFunc(response) where response is http's serverResponse of which i have the reference with me but i am not sure how can i pass the data param.
I am not understanding what is happening behind the scenes. Can anyone explain ? Do we encounter such kind of code often in javascript ?
EDIT:
To make things clear:
There is another method as follows:
function(data, response) {
response.writeHead(200, {
'Content-Type': 'application/json'
});
response.end(JSON.stringify(data));
}
which i call from my node server logic as follows:
http.createServer(function(req, res) {
// A parsed url to work with in case there are parameters
var _url;
// In case the client uses lower case for methods.
req.method = req.method.toUpperCase();
console.log(req.method + ' ' + req.url);
if (req.method !== 'GET') {
res.writeHead(501, {
'Content-Type': 'text/plain'
});
return res.end(req.method + ' is not implemented by this server.');
}
if (_url is something like //localhost:1337/employees) {
//call employee service which returns *data*.
// send the data with a 200 status code
return responder.sendJson(data, res);
});
} else {
// try to send the static file
/*res.writeHead(200);
res.end('static file maybe');*/
console.log('Inside else');
var staticInner = responder.staticFile("D:\\Node Applications\\public\\home.html");
staticInner(res);
}
// res.end('The current time is ' + Date.now())
}).listen(1337, '127.0.0.1');
As one can see there is no data variable to pass to the innerFunc hence, got confused.

According to the "innerFunc", it seems like data is some string that, being concatenated with staticPath, forms a path to a file. As we can see, that path is tested with fs.stat. Maybe the client is supposed to send some custom data? At any rate, data seems to be a pretty bad name for a variable like that.
It seems like what that function is trying to do is to send a file as response? What staticPath is supposed to be is a path relative to the Javascript file where this code is, because it is concatenated like this:
data = '.' + staticPath + data;
That would end in something like ./some/path/index.html. staticPath's value would be /some/path and data's value would be index.html. So if your JS file is in /home/foo/node/index.js, the file that the "innerFunc" will try to find would be in /home/foo/node/some/path/index.html.
If you pass "D:\\Node Applications\\public\\home.html" to staticFile() as you're doing, you would get something like .D:\\Node Applications\\public\\home.htmlindex.html which is clearly an invalid file.
To answer what's the point of a function returning a function
In this case, as mgouault said, it makes no sense at all to do that. Maybe the programmer had something in mind but changed it while programming this and the function ended up like that (it sometimes happen).

Your functions (ex: function(staticPath)) should either have a name or be stored in a variable to be able to call them. So I will guess that you are storing all this code in the variable staticFile.
Then when you call it with a parameter: staticFile("D:\\Node Applications\\public\\home.html") it returns a function (return function(data, response) {...}).
Now that you have this inner function you can call it with data and response:
var innerFunc = staticFile("D:\\Node Applications\\public\\home.html");
innerFunc(data, response);
Which will responds using your variable response (I guess).
A function returning a function is frequent in javascript especially when using closures for certains purposes, but in this case it's not really useful.

Related

Changing req object within api server?

I recently picked up a client who has a dev team. I am working on a website that has already been developed and am running into some things that are slightly strange to me.
I've always though it was essentially bad to mess with the request object within route handling (I could be completely wrong here).
The following code reaaaaally confuses me as I am not sure why they are assigning the req.query.msg to something instead of just creating a variable and passing it through on the ejs page render.
/********************************************************
* *
* CHANGE PASSWORD ROUTE THAT POSTS THE NEW PASSWORD TO *
* DATABASE. *
* *
********************************************************/
app.post('/client/password', function (req, res) {
var url = URLS.ClientChangePW;
if(req.session.securityquestions[0].SSN !== "null" || req.session.securityquestions[0].SSN !== "undefined"){
if(req.body.pwd !== req.body.pwdconf){
res.redirect('/client/changePassword' + config.PWD_MISMATCH);
} else {
var ssn = req.session.securityquestions[0].SSN;
while(ssn.length < 9){
ssn = "0" + ssn;
}
url = url.replace("#ssn", ssn);
url = url.replace("#newpw", req.body.pwd);
}
request.put(url, function (err, xres, body) {
var data = JSON.parse(body);
if(data.status === 200){
email(req.session.securityquestions[0].EMAIL, "none", "forgotpw", function(result){
if(result){
req.query.msg = "Your password has been reset.";
} else {
req.query.msg = "Request unsuccessful. Please call number here for assistance.";
}
res.render('pages/login', {
session: req.session,
msg: req.query.msg
});
});
} else {
req.query.msg = "Request unsuccessful. Please call number here for assistance.";
res.render('pages/login', {
session: req.session,
msg: req.query.msg
});
}
});
}
});
Again, I have never really messed with the req object so I could be wrong. I always thought the client sets up the request and we use that to send a response.
I am not sure why they are assigning the req.query.msg to something instead of just creating a variable and passing it through on the ejs page render.
There does not appear to be any reason to be assigning to the req.query.msg property here. If this were my code, I'd be using a separate local variable for it.
Again, I have never really messed with the req object so I could be wrong. I always thought the client sets up the request and we use that to send a response.
Though this is not what is happening here, it is common in Express development to use middleware that sets state on the req object for request handlers further down the routing stack to use. The req object is the canonical object where you keep request-specific state while processing the request. If you only have one request handler function working on the request, then there's no reason to put state on the req object as you can just use local variables in that one request handler function. But, if you're using middleware whose job it is to set things up before ultimately getting to a request handler, then the req object is where that setup state is usually put. You'll notice that req.session is also used in this code. That .session property was put there by some middleware upstream in the request processing.
So, it IS common to add state to the req object when using middleware. But, in the .msg property example in the code you show, there is no particular reason to put that on the req object as its value is only needed in the local function so it can just as easily (and I would argue more clearly) be in a local variable.

Using Cheerio and Response for Node web scraper, passing response function result to the view

I'm using this tutorial :
https://www.smashingmagazine.com/2015/04/web-scraping-with-nodejs/
To make a really basic node web scraper. I have my app set up and running here:
https://[redacted]/
What it is currently doing behind the scenes in my node app, is using the two modules cheerio and request to run this function (below). This function basically takes a URL, makes the request and grabs an element of the page with a data variable, scrapes the value of it, and logs the value, (temperature) to the console of my terminal of my computer. I need a way to send this value to my view and render it on the page instead of just logging it to the console of my computer.
The problem I'm having is that the scope of the request function below, I can't pass any of the return values, (temperature) to my view. I know there is something wrong with my set up because I currently have the request function INSIDE of my router.get. If I put the request function outside the router.get, I still cant pass the values to my view but it will successfully get the data from the web url and log it to my terminal's console. I hope I am being clear. Please see the res.render to my view which wraps the request function that is doing the web scraping..
router.get('/', function(req, res, next) {
//target url we are scraping data from
var url = "http://www.wunderground.com/cgi-bin/findweather/getForecast?&query=" + 02888;
var temperature;
// request function that uses the request module
request(url, function (error, response, body) {
if (!error) {
// using cheerio module to load body of html req document and scrape the data
var $ = cheerio.load(body),
temperature = $("[data-variable='temperature'] .wx-value").html();
// logs it to console (of my computer..)
console.log("It’s " + temperature + " degrees Fahrenheit.");
}
else {
console.log("We’ve encountered an error: " + error);
}
return temperature;
});
/* renders my view, this is my attempt to pass the values as variables to my handlebars template. Currently it is only passing the URL var as it exists before the request function call, and the empty var temperature (which gets its value during, and inside the request function call). How can i get at those values returned from the request function and pass to my view below? */
res.render('index', {title: url, data: temperature } );
});
The function in request is a executed asynchronously, so as you have it, render is getting called before temperature is set. You need to move the render function into the async function.
router.get('/', function(req, res, next) {
//target url we are scraping data from
var url = "http://www.wunderground.com/cgi-bin/findweather/getForecast?&query=" + 02888;
var temperature;
// request function that uses the request module
request(url, function (error, response, body) {
if (!error) {
// using cheerio module to load body of html req document and scrape the data
var $ = cheerio.load(body),
temperature = $("[data-variable='temperature'] .wx-value").html();
// logs it to console (of my computer..)
console.log("It’s " + temperature + " degrees Fahrenheit.");
}
else {
console.log("We’ve encountered an error: " + error);
}
res.render('index', {title: url, data: temperature } );
});
});

Need help understanding Node.js in respect to routing using a JavaScript API?

I understand the basics of routing in Node.js and using the http module for it. I understand all the Node.js code below but just the JavaScript API part and how it is used to make the routing code much more cleaner is what I have trouble understanding. When I say "trouble understanding" I mean trouble understanding the syntax and how the routes object is used.
The code is from an E-book I have been learning from so please read the code below.
var http = require("http");
var url = require("url");
var route = {
routes : {},
for: function(path, handler){
this.routes[path] = handler;
}
};
route.for("/start", function(request, response){
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello"); response.end();
});
route.for("/finish", function(request, response){
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Goodbye");
response.end();
});
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
if(typeof route.routes[pathname] ==='function'){
route.routes[pathname](request, response);
}else{
response.writeHead(404, {"Content-Type": "text/plain"});
response.end("404 Not Found");
}
}
http.createServer(onRequest).listen(9999);
console.log("Server has started.")
My understanding so far is that: route.routes is an empty object and route.for is a function. The function has two parameters function(path,handler) but I don't understand the part in the function i.e. this.routes[path] = handler;
From my understanding this.routes[path] is an empty object so is the code setting handler to an empty object?
and beyond this I have absolutely no clue what function onRequest(request,response){}; is doing.
Plase explain the whole code for me as I find it very disturbing not being able to understanding the basics before progressing through the E-book.
Http module that you include in first line has createserver function that takes a function as a parameter. In of the last lines we pass "onRequest" function to it. The function passed is internally invoked by http module whenever request is recived on port 9999 as also defined. Function onRequest is invoked with two parameters one is "request" that contains data like headers and body of a request that was recived. 2nd parameter is respons object it is whats sent back. It has functions that facilate this like writeHead which writes headers, .end which signals http module to sned the response finally back.
onRequest function can do whatever it wants with the request and send whatever response it wants to send back.
Here it using url module that is native to nodejs parses url and extract pathname which is everything after first / so www.mydomain.com/thispart/andthis...etc are extracted.
Then thus is done to do object lookup inside the routes. If object with key that is equal to string of this pathname exists it will return the value that is the function and if not the expression will evaluate to false and 404 part will be run. Upon match function gets invoked with response and request objects that onRequest got in the parameters.
In Javascript property of an object can be set even if its not present..
var a = {n:1};
a.x = "exists";
console.log (a.x); //exists

Json returns undefined in nodeJs and AngularJs

I've got an app which makes calls to an api and shows data about that info: first, it takes a username from an input in the client and posts it to the server. In this step if I check if the data has been sent alright to the server everything seems fine.
AngularJs part:
var app=angular.module("app",[])
app.controller("InfoController",['$scope','$log','$http','$filter',function($scope,$log,$http,$filter){
$scope.info = {
summonerName: '',
};
$scope.info.onClick = function(){
$scope.info.summonerName = $scope.info.summonerNameBox;
$http.post('/api/getSummonerName', $scope.info);
$http.get('/api/summonerData')
.success(function(data, status){
$scope.info.display = data;
}).error(function(data,status){
alert("Error: " + status);
});
};
}])
Nodejs:
var summonerName;
var summonerId = '';
app.post('/api/getSummonerName', function (req, res){
summonerName = req.body.summonerName;
console.log("Post getSummonerName " + summonerName);
});
app.get('/api/summonerData', function(req,res){
LolApi.Summoner.getByName(summonerName, function(err, summoner) {
if(!err) {
res.json(summoner);
summonerId = req.body.summoner;
console.log(summonerId);
if(err)
res.send(err)
}
})
});
When I have this data in the server, I make a call to an api for getting this user's info, and everything goes fine as well.
The problem comes when I want to store an specific field from this json. When I want to store it in a variable, everything I get is "undefined" :/ (Once I achieved getting "[Object object]", but can't get it anymore...)
Any idea?
Thank you all.
In my opinion, this isn't the way you should do it.
If you want to do a get on a summoner, you need to just use the get method.
Especially if you're dealing with multiple users.
You might want to pass data in the get request like specified in this answer and ditch the post request:
AngularJS passing data to $http.get request
That way, you're not dependent on the memory and you're able to modularize it :)

JSONP call with server-side language as Javascript

I've been trying to use JSONP to get a JSON object from a server via a client-side call (on a different port). However, because my server is implemented in javascript using Node.js and Express, I haven't been able to find much on JSONP with Javascript on the server as most sites I found used php for server-side code.
I believe the issue is with how I set up the url with respect to the callback, which I'm a bit fuzzy on cause it's new to me.
On the server:
//Setting up server stuff
var express = require('express'),
app = express.createServer();
app.use(express.logger());
//Making a connection to the mongoDB to get the data that I want to display in the JSON object
new Db('prism',
new Server("127.0.0.1", 27017, {auto_reconnect: false}), {}).open(function(err, db) {
app.get('/getData', function(req, res) {
console.log('JSONPCALLBACK CALLED WITH RETURNDATA PASSED IN; SERVER SIDE');
if (typeof callback == 'function') {
console.log('callback is defined');
callback(returnData);
}
else {
console.log('callback is not defined');
}
}
});
And on the client:
$.ajaxSetup({ cache : false });
$.getJSON('http://127.0.0.1:1337/getData&callback=?', function(rtndata) {
console.log('SUCCESS');
console.log(rtndata);
});
embedded by the standard tags.
But I get the error:
GET http://127.0.0.1:1337/getData&callback=jQuery16108897686484269798_1311007334273?_=1311007334342 404 (Not Found)
The server is on port 1337 while the client is run through MAMP on localhost:8888. I'm not sure if its even a localhost related issue as I've been trying to get this setup running for a few days now.
I believe the issue has something to do with not writing this line, which is in php, into my server-side Javascript. Most of the JSONP examples I found had something like this. But I'm not sure.
if ($GET['callback'] != '')
$json = $GET['callback']."( $json )";
return $json;
Any help would be greatly appreciated. I apologize ahead of times for being super verbose.
Bests,
Cong
I think you have two problems. First is the 404. Completely separate from getting the client-side jQuery code to work, you need to make sure that you can issue a regular browser request (i.e. paste in that URL) and get back what you expect. I haven't used express, so it's hard for me to comment on why you'd be getting that, except to say that I don't see 1337 anywhere in your server-side code, just what appears to be the port number 27017.
The second problem is that you don't actually want to execute the callback on the server, just build the JSON response including the callback (string) prefixed to it.
So instead of this ...
if (typeof callback == 'function') {
console.log('callback is defined');
callback(returnData);
}
else {
console.log('callback is not defined');
}
try this:
if (callback) {
console.log('callback is defined');
res.write(callback + '(' + JSON.stringify(returnData) + ')');
}
else {
console.log('callback is not defined');
}
Hope this helps!
From http://api.jquery.com/jQuery.getJSON/ there is an example that includes 2 '?' in the URL.
you only have one, so try
$.getJSON('http://127.0.0.1:1337/getData?callback=?', function(rtndata) {
and see if that gets rid of your 404
then look #jimbojw suggestion for returning a proper jsonp formated responce.
Use this:
var express = require("express");
var server = express.createServer();
server.enable("jsonp callback");
server.get("/foo", function(req, res) {
// this is important - you must use Response.json()
res.json("hello");
});
jsonp with node.js express

Categories

Resources