Maintaining es6 class state over requests with express router - node.js

I recently tried updating my project code structure with es6 classes in nodejs.
Here's what a controller class look like
class TaskController {
constructor(io, redisClient) {
this.socket = io;
this.redisClient = redisClient;
}
create(req, res) {
let taskDetails = req.body;
taskDetails.owner = req.user.id;
let errorFields = Validation.validate(taskDetails, [
{ name: 'title', type: 'text' }
]);
if (errorFields.length > 0) {
return ErrorHandler.handleError(res, errorFields);
}
...`
}
}
and Here's how I'm initializing the class in a routes file
module.exports = (app, io, redisClient) => {
let taskController = new TaskController(io, redisClient);
router.post('', middlewares.isAuthorized('task:create'), taskController.create);
app.use('/api/tasks', middlewares.isAuthenticated(), router);
};
The problem is while hitting the create api the this object is undefined in the create function.
With a little debugging, I know that the constructor is called when registering the routes.
But the taskController looses context when the create function is actually called.
How can I make it work with this structure or do I have to revert back to
module.exporting every function task controller?

You can use bind method to bind context. while passing create function.
router.post('', middlewares.isAuthorized('task:create'), taskController.create.bind(taskController));
create method is losing context because it is getting called in different scope by post method.
You can bind context using bind method which returns a function and pass that function to create method.

Related

I want to use Values getting from custom middleware in my service class constructor of FeathersJS

I have following custom middleware in my feathersjs project.
const { envConfig } = require('url-config');
module.exports.envCfg = function (options = {}) {
return async function () {
const config = await envConfig('mongodb://localhost:27017', 'dbname');
}
}
I want to use config from my middleware in one of service constructor. I also have 1 method in my require('url-config') which returns same value but since code inside my envConfig is executed asynchronously and It has to be called during app start only I cant get it in service.
One possible way is to add it to your app instance. You can copy how feathers do the app.configure().
module.exports = async function(){
app = this;
app.envConfig = await envConfig('mongodb://localhost:27017', 'dbname');
}

sinon stub namespaced function

I'm having some issues using sinon stubs and it may stem from how I'm implementing namespacing on the module that I'm looking to stub. Methods directly defined on the prototype are stubbed as I would expect.
...my module.js
const Constructor = require('./constructor') //...just exports a singleton
/* Need to namespace some of my functions and retain the `this` context */
Object.defineProperty(Constructor.prototype, 'es', {
get: function() {
return {
method: require('./implementations/doesSomething.js').bind(this)
}
}
});
module.exports = Constructor;
/* ...testFile.js */
const Constructor = require('./constructor');
const instance = new Constructor();
const sinon = require('sinon');
sinon.stub(instance.es, 'method', function() {
return 'hijacked original method'
});
As mentioned on the Sinon issue tracker, the problem here is that using a plain Object.defineProperty(obj, 'prop') call does something else than plainly creating it using assignment (obj['prop'] = ...).
Generally, if you try defining your property without Object.defineProperty it will be stubbable, but using defineProperty (without creating a special configuration) will make it impossible to stub the property. The reason is simply that the default values for writeable and configurable are false! You cannot delete them or change them. And if you can't do that, then Sinon won't help you. So, generally, you need to add writeable: true, configurable: true in your property definition.
Now there was one more thing I forgot to answer originally:
You are not trying to wrap a function on Constructor.prototype.es.method - what you are trying to wrap is the function on the object returned by the getter on the property for es. That will never work. Why? Simply because the returned object is never the same. You are creating a new object around method each time. If you really need to replace/stub the method property, you actually need to replace the entire Constructor.prototype.es property instead. If you need this namespacing, you can vastly simplify this, and also enable stubbing, like this:
Constructor.prototype.es = {};
Object.defineProperty(Constructor.prototype.es, 'method', {
get: function() {
return someFunction.bind(this);
},
writeable: true,
configurable:true
}
An expanded, fully working example (Gist for download):
// constructor.js
const someFunction = function(){
return this.value;
}
function Constructor(){ };
Constructor.prototype.es = { value : 100 };
Object.defineProperty(Constructor.prototype.es, 'method', {
get: function() {
return someFunction.bind(this);
},
writeable: true,
configurable:true
});
// test.js
const instance = new Constructor();
console.log(instance.es.method()) // => 100
// using this won't work:
// sinon.stub(instance.__proto__.es, 'method').returns(42);
// because the getter is returning a _new_ function each time
// therefore you need to attack the actual getter function:
const stub = sinon.stub(instance.__proto__.es, 'method').value(()=>42);
console.log(instance.es.method()) // => 42
stub.get(()=>()=>84);
console.log(instance.es.method()) // => 84
stub.restore();
console.log(instance.es.method()) // => 100
// the above is working on the prototype, can't we do this on the instance?
// yes, we can, but remember that the `es` object is shared, so we
// can avoid modifying it by shadowing it further down the prototype
instance.es = { method: sinon.stub().returns(256) };
console.log(instance.es.method()) // => 256
delete instance.es
console.log(instance.es.method()) // => 100
<script src="https://unpkg.com/sinon#2.3.5/pkg/sinon.js"></script>

Scope in NodeJS / Firebase promise

I'm trying to develop a NodeJS app connecting to Firebase. I can connect successfully, but I'm unable to figure how to manage the scope in the then call.
I'm using NodeJS 6.9.2
My test implementation looks like this:
const EventEmitter = require('events');
const fb = require('firebase')
class FireGateway extends EventEmitter {
constructor() {
super();
if ( this.instance ) {
return this.instance;
}
// INIT
var fbConfig = {
apiKey: "xxxxx",
authDomain: "xxxxx.firebaseapp.com",
databaseURL: "https://xxxxx.firebaseio.com/"
};
fb.initializeApp(fbConfig)
this.instance = this;
this.testvar = "aaa";
}
login() {
fb.auth().signInWithEmailAndPassword ("email", "pwd")
.catch(function(error) {
// Handle Errors here.
}).then( function(onresolve, onreject) {
if (onresolve) {
console.log(this.testvar);
// "Cannot read property 'testvar' of undefined"
this.emit('loggedin');
// error as well
}
})
}
}
module.exports = FireGateway;
------
...
var FireGateway = require('./app/fireGateway');
this.fireGW = new FireGateway();
this.fireGW.login();
....
Any idea how can I manage it?
The callback passed to then is being called asynchronously from another context, so the this doesn't correspond to the instantiated object.
Using ES6 arrow functions you can keep your object context, since an arrow function does not create its own this context.
By the way, the syntax you are using in the then method is not correct, then accepts two callbacks with one argument each one. Check the syntax here.
The catch before the then is not necessary as well I think, it would make more sense to put it at the end.
It would be something like this:
login() {
fb.auth().signInWithEmailAndPassword("email", "pwd")
.then(
(onResolve) => {
console.log(this.testvar);
this.emit('loggedin');
},
(onReject) = > {
// error handling goes here
});
}
On the other hand, it seems login method is doing an asynchronous operation, so you might want to wait for it to finish in your code. I would make the login method return a Promise, so you can wait for it outside:
login() {
return fb.auth().signInWithEmailAndPassword("email", "pwd")
...
}

Getting the Restify Handler Object using "this"

I set up a Restify route using the following code. I create a pseudoclass, instantiate the object and use that as the handler. I want the object itself to be bound to "this" in the "ping" function so I have access to the member variables. However, "this" ends up pointing to some restify object that contains routes, etc. Is this something that just won't work with Restify?
var Handler1 = function() {
if (!(this instanceof Handler1 )) {
return new Handler1 ();
}
...
}
HttpHandlers.prototype.ping= function(req, res, next) {
//this doesn't point to the handler1 object.
return next();
}
...
var myhandler1 = new Handler();
app.get("/ping", myhandler1.ping , handler2);
handler1.ping.bind(myhandler1 )
I would try giving an object instance as the route instead of the object. That makes bit more sense to me.
class Pong1 {
constructor(name) {
this.name = name;
}
ping = res => res.write(`PONG ${this.name}`);
}
const pong1 = new Pong1('Pongy);
app.get('/ping', pong1.ping);
This is more like an ES2017 version, which I think is preferable. You should be able to convert to a more ES5 syntax if you really want.
It turns out that I needed to pass in the bound function:
app.get("/ping", myhandler1.ping.bind(myhandler1), handler2);

How to access instance variables anywhere in the class for node.js

I am working on a node.js application with postgresql, using the express framework. I am trying to follow MVC as much as possible.
I want to generate query results in a model class and then pass them to a controller class. That controller class is actually defined in the routes, so that controller class can take the results and pass them as http response.
This is my database helper class, i.e. the model class. My problem is at the listener at the very end of the class.
exports.DatabaseHelper = function()
{
var allVenues;
var client;
var customEventEmitter;
this.init = function()
{
this.customEventEmitter = new events.EventEmitter();
client = new pg.Client(
{
host:'localhost',
port:5432,
database:'postgres',
user:'postgres',
password:'password'
});
}
this.getVenuesWithEvents = function(searchParams)
{
allVenues = new Array();
var query_for_venues;
this.init();
client.connect();
client.addListener("error",function()
{
sys.puts("postgresql interface error");
});
query_for_venues = client.query("select id, name, location, latitude, longitude, category_generalized from venues");
query_for_venues.addListener("row",function(row)
{
//some code
});
query_for_venues.addListener("end",function(result)
{
this.customEventEmitter.emit("data",allVenues);
//////////////////////////////////////////////////////////
//this line shows error....'this' refers to the query object so customEventEmitter is undefined
//customEventEmitter is my idea of sharing the query results to my controller class.
//but I cannot do this becasue of this error
console.log("after emission");
});
}
}
How can I access the customEventEmitter instance variable from within the listener?
Just remove this from your init function:
this.customEventEmitter = new events.EventEmitter();
So you'll have:
customEventEmitter = new events.EventEmitter();
And in your listener just emit the emitter without this as follows:
query_for_venues.addListener("end",function(result){
customEventEmitter.emit("data",allVenues);
console.log("after emission");
});
let me show you a nice trick.
you could change custom
var customEventEmitter;
to
this.customEventEmitter =null;
at the top of the function. then you can call
var self = this;
outside of the query function. then inside the query function you reference the outer "this" with self.
as in:
self.customEventEmitter.emit()
the methodology I just described is standard.

Resources