user3564573
user3564573

Reputation: 700

Why am i getting this ... is not a function Error?

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

Answers (3)

Borys Serebrov
Borys Serebrov

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

Oka
Oka

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);
      });
   },

or Function.prototype.bind:

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

Mitch
Mitch

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

Related Questions