Node.js - accessing a const from a function within http.get - javascript

In the code below I am accessing the current bitcoin value in GBP. The console.log works fine.
value.js
http = require('http');
http.get({
host: 'api.coindesk.com',
path: '/v1/bpi/currentprice.json'
},
function get_value(response) {
// Continuously update stream with data
var body = '';
response.on('data', function(d) { body += d; });
response.on('end', function() {
// Data reception is done, do whatever with it!
var parsed = JSON.parse(body);
var final_value = parsed.bpi.GBP.rate
console.log(final_value)
module.exports = final_value;
});
}
);
However when I try to access this value (final_value) from another file:
server.js
PORT = 4000;
var http = require('http');
const value = require('./value.js');
var server = http.createServer((req, res) => {
res.write("Create server working");
});
server.listen(PORT, () => {
console.log(value);
});
All I get back is {}.
I'm quite new to node.js and more used to python. I've looked into accessing values from functions within functions but couldn't find any kind of solution.
Does anyone have a recommendation as to how I could access the variable final_value from a separate file?

I honestly prefer to use express than native Node, but given that you are using it, I can give you some tips to help you with it:
If you want to use a js file from other, you should export what you want to share between them. In the example that you are showing it should be something like this (note that I'm exporting the function and also using it as a Promise in a function):
const http = require('http');
module.export = function () {
return new Promise(function (resolve) {
http.get({
host: 'api.coindesk.com',
path: '/v1/bpi/currentprice.json'
},
function get_value(response) {
// Continuously update stream with data
var body = '';
response.on('data', function(d) { body += d; });
response.on('end', function() {
// Data reception is done, do whatever with it!
var parsed = JSON.parse(body);
var final_value = parsed.bpi.GBP.rate
console.log(final_value)
resolve(final_value);
});
}
);
});
}
then you can use it in your server file in this way:
...
server.listen(PORT, () => {
value.then(result => console.log(result));
});

You can change module.exports = final_value to exports.final_value = final_value, and then retrieve the value with
const { final_value } = require('./value.js');
...
server.listen(PORT, () => {
console.log(final_value);
});
The advantage of this is that you can now export other values from the value.js file, and just require them in the same way. The main difference between module.exports and exports.value is that module.exports is an object that has exports as a property, and exports is just an alias for module.exports. Essentially, by using the module.exports syntax, you are assigning module.exports the value of the object you are assigning to it.

Related

Use JSON Object for Function Pointer Mapping in NodeJS

I'm trying to learn Socket.io and I'm a beginner in NodeJS.
I'm using JSON object as a kind of key-value store for mapping callback function with relevant event names. May be there is some other alternative to do it efficiently which I don't know. The problem is in the code below, when I call bob.printName() it prints the JSON object perfectly. But when I call the same function using the callbacks['connection'](), it says the JSON object is undefined. I would like to know the reason of that and also love to know any other efficient alternatives like PHP like array indexing.
/***
** index.js
***/
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var User = require('./User');
var bob = new User();
var callbacks = {
'connection': bob.printName
};
io.on('connection', function(socket){
bob.printName();
callbacks['connection']();
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
/***
** User.js
***/
var jsonObj = null;
function User() {
this.jsonObj = {
type: 'type',
body: 'body'
};
}
User.prototype.printName = function(){
console.log(this.jsonObj);
}
module.exports = User;

node js prototype object 'self' var does not store correct context for callback

I am well experienced developer but new to java script and nodejs , I apologize if this question has been answered 'as-is' but even though I have went over multiple examples and stackoverflow answers , I did not find a simple complete example of prototypical class with correct 'self' var scoping and bind(this).
I tried both and both went wrong ... I will appreciate your help.
I tried putting
var self = this;
In beginning of my functions declarations , but when running , it does not actually go through the function code when it is set to the prototype , and so , 'this' is not set correctly.
/**
* Module Dependencies
*/
var cheerio = require('cheerio');
var http = require('http');
/**
* Export
*/
module.exports = SimplePageGetter;
function SimplePageGetter(pageLink) {
this._pageLink = pageLink;
}
SimplePageGetter.prototype.getPage = function () {
var self = this;
http.request(self._pageLink, self._resultsPageHttpGetCallback).end();
};
SimplePageGetter.prototype._resultsPageHttpGetCallback = function (response) {
var pageBody = '';
var self = this;
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
pageBody += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
self._parsePage(pageBody);
});
};
SimplePageGetter.prototype._parsePage = function (body) {
console.log('page parsed');
}
For some reason , 'self' is correct when calling getPage but will be http module ClientRequest and not the object on _resultsPageHttpGetCallBack .
What am I please doing wrong ?
Thank you ,
James
Setting self in the calling function doesn't do anything to change what this will be in the function being called. So looking at this:
SimplePageGetter.prototype.getPage = function () {
var self = this;
http.request(self._pageLink, self._resultsPageHttpGetCallback).end();
};
That's still just passing a reference to the self._resultsPageHttpGetCallback function to http.request. http.request will still call it as just a normal function, not a method, and so this in _resultsPageHttpGetCallback will be either undefined (strict mode) or the global object (loose mode).
The self pattern use useful for functions created in the same scope (or a nested scope), for instance:
function someMethod() {
var self = this;
http.request(self._pageLink, function(err, data) {
// Use `self` here to access object info
}).end();
}
That works because the anonymous function I'm passing into http.request closes over (has a reference to) the context where it's created, and that context has the self variable, and so the function can access the self variable.
For what you're doing, Function#bind would be more appropriate:
SimplePageGetter.prototype.getPage = function () {
http.request(this._pageLink, this._resultsPageHttpGetCallback.bind(this)).end();
};
Function#bind creates a new function that, when called, will call the original function with this set to a specific value.
More about this:
Here on Stack Overflow: How does the this keyword work?
On my anemic little blog: Mythical Methods | You Must Remember this
Just for reference, here's the Function#bind pattern applied to your complete code example:
/**
* Module Dependencies
*/
var cheerio = require('cheerio');
var http = require('http');
/**
* Export
*/
module.exports = SimplePageGetter;
function SimplePageGetter(pageLink) {
this._pageLink = pageLink;
}
SimplePageGetter.prototype.getPage = function () {
http.request(this._pageLink, this._resultsPageHttpGetCallback.bind(this)).end();
};
SimplePageGetter.prototype._resultsPageHttpGetCallback = function (response) {
var pageBody = '';
response.on('data', function (chunk) {
pageBody += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
this._parsePage(pageBody);
}.bind(this));
};
SimplePageGetter.prototype._parsePage = function (body) {
console.log('page parsed');
};
You might look into the new features of ES2015 (aka ES6), many of which you can use in NodeJS now as of v4 because the underlying V8 engine supports them (alternately, you can use a transpiler to produce ES5 code from ES6 input).
Here's the above using ES2015's:
...arrow functions, which inherit this from the context in which they're defined, making self unnecessary.
...the class keyword, which provides a more concise way to write constructors and prototypes.
...the let keyword, just because, you know, it's ES2015 code. :-)
Applying those:
/**
* Module Dependencies
*/
let cheerio = require('cheerio');
let http = require('http');
class SimplePageGetter {
constructor(pageLink) {
this._pageLink = pageLink;
}
getPage() {
http.request(this._pageLink, response => {
this._resultsPageHttpGetCallback(response);
}).end();
}
_resultsPageHttpGetCallback(response) {
let pageBody = '';
response.on('data', chunk => {
pageBody += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', () => {
this.parsePage(pageBody);
});
}
_parsePage(body) {
console.log('page parsed');
}
}
/**
* Export
*/
module.exports = SimplePageGetter;
Note that class is not hoisted like function declarations, so the standard place for exporting is usually at the bottom of the module. If you have just the one export (as you seem to in this case), though, you could do
module.exports = class SimplePageGetter {
//...
};
Last but not least: Unless you really need _resultsPageHttpGetCallback and _parsePage to be properties on the object (which are public), I would probably make them private functions instead, which either accept the SimplePageGetter instance as a standard argument, or expect to be called with this referring to it even though they aren't methods.
Here, they take an argument:
/**
* Module Dependencies
*/
let cheerio = require('cheerio');
let http = require('http');
class SimplePageGetter {
constructor(pageLink) {
this._pageLink = pageLink;
}
getPage() {
http.request(this._pageLink, response => {
resultsPageHttpGetCallback(this, response);
}).end();
}
}
function resultsPageHttpGetCallback(getter, response) {
let pageBody = '';
response.on('data', chunk => {
pageBody += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', () => {
parsePage(getter, pageBody);
});
}
function parsePage(getter, body) {
console.log('page parsed');
}
/**
* Export
*/
module.exports = SimplePageGetter;
Here, they expect this to be set, so we call them via Function#call:
/**
* Module Dependencies
*/
let cheerio = require('cheerio');
let http = require('http');
class SimplePageGetter {
constructor(pageLink) {
this._pageLink = pageLink;
}
getPage() {
http.request(this._pageLink, response => {
resultsPageHttpGetCallback.call(this, response);
}).end();
}
}
function resultsPageHttpGetCallback(response) {
let pageBody = '';
response.on('data', chunk => {
pageBody += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', () => {
parsePage.call(this, pageBody);
});
}
function parsePage(body) {
console.log('page parsed');
}
/**
* Export
*/
module.exports = SimplePageGetter;

How to mock http.ServerResponse and http.IncomingMessage for express.static

I've had no trouble testing my own route handlers but in this case I want to test express's static handler. I can't for the life of me figure out why it's hanging. Clearly there's some callback I'm missing or some event I need to emit.
I tried to make the smallest example I could.
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function createRequest(req) {
var emitter = new events.EventEmitter();
req.on = emitter.on.bind(emitter);
req.once = emitter.once.bind(emitter);
req.addListener = emitter.addListener.bind(emitter);
req.emit = emitter.emit.bind(emitter);
return req;
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = createRequest({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
Setup,
mkdir foo
cd foo
mkdir test
cat > test/test.js # copy and paste code above
^D
npm install express
npm install mocha
node node_modules/mocha/bin/mocha --recursive
it just times out.
What am I missing?
I also tried making the request a Readable stream. No change
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function MockMessage(req) {
stream.Readable.call(this);
var self = this;
Object.keys(req).forEach(function(key) {
self[key] = req[key];
});
}
util.inherits(MockMessage, stream.Readable);
MockMessage.prototype._read = function() {
this.push(null);
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = new MockMessage({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
I've still been digging. Look inside static-server I see it creates a Readable stream by calling fs.createReadStream. It does effectively
var s = fs.createReadStream(filename);
s.pipe(res);
So trying that myself works just fine
it('test stream', function(done) {
var s = fs.createReadStream(__dirname + "/test.js");
var res = new MockResponse(responseDone);
s.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
I thought maybe it's something about express waiting for the input stream to finish but that doesn't seem to be it either. If I consume the mock input stream with the response it works just fine
it('test msg->res', function(done) {
var req = new MockMessage({});
var res = new MockResponse(responseDone);
req.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
Any insight what I might be missing would be helpful
Note: while suggestions for 3rd party mocking libraries are appreciated I'm still really looking to understand what I'm missing to do it myself. Even if I eventually switch to some library I still want to know why this isn't working.
I found two issues that prevent the finish callback from being executed.
serve-static uses send module which is used to create file readstream from the path and pipe it to res object. But that module uses on-finished module which checks if finished attribute is set to false in response object, otherwise it destroys the file readstream. So filestream never gets a chance to emit data event.
express initialization overwrites the response object prototype. So the default stream methods like end() method is overwritten by http response prototype:
exports.init = function(app){
return function expressInit(req, res, next){
...
res.__proto__ = app.response;
..
};
};
To prevent this, I added another middleware right before static middleware to reset it back to MockResponse prototype:
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype; //change it back to MockResponse prototype
next();
});
Here are the changes made to make it work with MockResponse:
...
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
};
...
describe('test', function() {
var app;
before(function() {
app = express();
//another middleware to reset the res object
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype;
next();
});
app.use(express.static(__dirname));
});
...
});
EDIT:
As #gman pointed out, it is possible to use direct property instead of prototype method. In that case the extra middleware to overwrite prototype isn't necessary:
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
//using direct property for _write, write, end - since all these are changed when prototype is changed
this._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
this.write = stream.Writable.prototype.write;
this.end = stream.Writable.prototype.end;
};
It appears my answer is not complete. For some reason the app works only if the file is not found. First thing to debug is do the following in your shell (or cmd):
export DEBUG=express:router,send
then run the test, you'll get more info.
Meanwhile I am still looking into this, for now, ignore my answer below.
----------- ignore this till I verify that it does work -----------
It seems like express static does not favor the absolute path you give it (__dirname).
Try:
app.use(express.static('.'));
and it will work. Note that your current dir for the mocha runner is 'test/'
I have to admit this is quite a mistery. I tried 'fulling' it by doing:
app.use(express.static(__dirname + '/../test')
but still it didn't work. Even specifying a full path did not solve this. Strange.

Prototype handler not initiating on custom emitter

In the following code I'm expecting console.log to output the data that is passed along with the custom emitter 'output' but that's not occurring. From what I can tell Looper.prototype.output is called properly from withing the server handler but it's not responding to the emitter 'output' event that's defined in Looper.prototype.run. Why isn't my output event handler recognizing these events?
var express = require('express');
var http = require('http');
var spawn = require('child_process').spawn;
var util = require('util');
var fs = require('fs');
var EventEmitter = require("events").EventEmitter;
var sys = require("sys");
function Looper(req) {
this.req = req;
EventEmitter.call(this);
}
sys.inherits(Looper, EventEmitter);
Looper.prototype.run = function() {
var cmd = spawn('./flow',[this.req]); // <-- script that outputs req every second
cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
this.emit('output',data);
});
}
Looper.prototype.output = function(callback) {
this.on('output', function(data) {
return callback(data.trim());
});
}
var looper = new Looper('blah');
looper.run();
var app = express();
var webServer = http.createServer(app);
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.send(
"<h1>hello world</h1>"
);
looper.output(function(res) {
console.log('blah');
console.log(res);
});
});
webServer.listen(3000);
Looper.prototype.run = function() {
var cmd = spawn('./flow',[this.req]); // <-- script that outputs req every second
cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
this.emit('output',data);
// ^ not what you think it is.
});
}
I think that this is not what you think it is in that callback. You need to capture the value of this outside of the callback first.
Looper.prototype.run = function() {
var self = this; // save this
var cmd = spawn('./flow',[this.req]); // <-- script that outputs req every second
cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
self.emit('output',data); // use previously saved value of this
});
}
Otherwise, this would default to the global object, and when the global object emits an event, noone is listening to it.

JS - passing a connection(object) from one function to another

I am new to JS and I have a simple question. I am writing a node_redis code to connect to the db.
I have created a db module in which there is an init function to start the connection.
the module also has another function which queries the db. for the query, i will need the connection (dbConnection) object from the first function and then use it in the 2nd function. how do i do this? I can get it done by using global variables but most places tell me its a bad idea.
Sorry if the question is stupid, I am learning how to code. results in google tell me that it can be done by passing it as an object property. But i don't know if it is the proper way to do things in my context, or even how to do it.
var redis = require('redis');
module.exports = redisDb = {
// Initialize the module. Invokes callback when ready (or on error)
init: function(config, callback) {
// Open the database connection
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Connected!");
console.log(dbConnection.keys('*'));
});
dbConnection.on('connect' , log('connect'));
dbConnection.on('ready' , log('ready'));
dbConnection.on('reconnecting', log('reconnecting'));
dbConnection.on('error' , log('error'));
dbConnection.on('idle' , log('idle...'));
dbConnection.on('end' , log('end'));
function log(type) {
return function() {
console.log(type, arguments);
}
}
callback("callback - Connected");
},
getValue: function(key, callback) {
dbConnection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
};
EDIT:
tried another way. still failing.
module.exports = redisDb = (function() {
var config = require('../config');
var redis = require('redis');
return {
connection: function(config) {
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Authenticated!");
});
return dbConnection
},
getValue: function(connection, callback) {
connection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
}
})();
Now one way is as you said to make dbConnection an object Property.
The other way is to call init() in getValue() which results in establishing different connection every time you want some value.
Because a DB Connection is a valuable resource, I'd say it's better to use the second variant.
Of course then you'll need to return dbConnection from init().
PS: Global variables were made initially for such things and then people saw that fewer they are the better. That's why using global vars is considered a bad style.
I made the code work by simply declaring the connection in the parent function.
module.exports = _redisDb = (function() {
var redis = require('redis');
var config = require('../config');
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Authenticated!");
});
var getValue = function() {
dbConnection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
return {
getValue: getValue
}
})();
While the above work,s I'd still like for someone to tell me how can I pass variables/objects between functions off the same module.

Categories