Reputation: 700
I am exporting an object. Here is my file named "token.js"
var jwt = require('jsonwebtoken');
const secret = "mysecret"
module.exports = {
generate : function(id){
return jwt.sign({id:id},secret);
},
verify : function(token, callback){
jwt.verify(token, secret,callback);
},
authenticateUser: function(req,res,next){
var token = req.method =="GET" ? req.query.token : req.body.token;
if(!token) return this.authenticationFailure (req,res);
this.verify(token, function(err,user){
if(err) return this.authenticationFailure (req,res);
req.body.user = user;
next();
});
},
authenticationFailure : function(req,res){
res.json({response:"Failed to authenticate"});
}
}
Then from my app i request this file, the generate method and verify method works fine is called from the api directly. The problem comes when i call authenticateUser, the method is called but it when the method called "this.authenticationFailure" or "this.verify" it returns an error that they are not functions. They appear as functions to me, what am I doing wrong?
Upvotes: 0
Views: 1343
Reputation: 16172
Your authenticateUser
method is probably used like this:
something(yourModule.authenticateUser);
Where something
does this:
funcation something(callback) {
...
callback(req, res, next);
}
Here you see, that callback
is called on its own, not as a method of the object, so the original this
is lost.
General soulution is to catch this
to some variable to be able to get it later.
Here you can use the module object itself:
var myModule = {};
module.exports = myModule;
myModule.authenticateUser = function(req,res,next){
var token = req.method =="GET" ? req.query.token : req.body.token;
if(!token) return myModule.authenticationFailure (req,res);
myModule.verify(token, function(err,user){
if(err) return myModule.authenticationFailure (req,res);
req.body.user = user;
next();
});
};
myModule.authenticationFailure = function(req,res){
res.json({response:"Failed to authenticate"});
};
Inside the authenticateUser
you use myModule
variable instead of this
.
Upvotes: 0
Reputation: 26355
When the callback provided to this.verify
is executed, its contextual this
will be different from your module.exports
object. Every function in JavaScript has a contextual this
, but this
defaults to the global object when not otherwise bound. In your callback function, no contextual this
is bound.
You need to maintain that context. There are a few ways to achieve this.
ES5?
The self = this
style:
authenticateUser: function(req,res,next){
var self, token = req.method =="GET" ? req.query.token : req.body.token;
if(!token) return this.authenticationFailure (req,res);
self = this;
this.verify(token, function(err,user){
if(err) return self.authenticationFailure (req,res);
});
},
authenticateUser: function(req,res,next){
var token = req.method =="GET" ? req.query.token : req.body.token;
if(!token) return this.authenticationFailure (req,res);
this.verify(token, (function(err,user){
if(err) return this.authenticationFailure (req,res);
}).bind(this));
},
The ES6 solution is to use fat arrow functions, which maintain the contextual this
of their parent scope.
authenticateUser: function(req,res,next){
var token = req.method =="GET" ? req.query.token : req.body.token;
if(!token) return this.authenticationFailure (req,res);
this.verify(token, (err,user) => {
if(err) return this.authenticationFailure (req,res);
});
},
Take a look at the MDN articles on this
, Function.prototype.bind
, Function.prototype.call
, and Function.prototype.apply
for a better understand of how contexts work.
Upvotes: 0
Reputation: 321
Add var self = this;
in your functions and use self
wherever you would have used this
.
This will ensure your "this" context is consistent.
Upvotes: 2