0

I've recently started to use Promises, and I still don't get a few things.

Let me give you the following example.

In a Node & Mongo application I am trying to implement an action that authenticates a user with a jwt token. The request has two parameters userName and passWord. What I need to do is to:

1) Verify if the users exists in the database 2) If the users exists verify if the hashed password from the database matches the password supplied in plain text from the request 3) If the two passwords are matching generate a jwt token from the user object I've obtained from the database.

For step 1) I've configured mongoose to use Q promises. For step 2) I am using bcrypt to compare the two passwords, and for the step 3) I am using the node jwt package to generate the token.

I've isolated the code like this (it's only a proof of concept):

// *** INSIDE AN API OBJECT *** //

 action : function(req, res) {
            return  User.findOne({ userName : req.body.userName }).exec()
                    .then(function(user){
                        // If the user doesn't exist return invalid credentials
                        var defer = Q.defer();
                        if (user) defer.resolve(user);
                        else defer.reject(new CError(400, E.INVALID_CREDENTIALS));
                        return defer.promise;
                        // returns user
                    })
                    .then(function(user){
                        // See if the password matches the hash
                        return Q.nfcall(bcrypt.compare(req.body.passWord, user.passWordHash);
                        // Returns true || false
                    })
                    .then(function(result){
                        // How do I obtain the user that was calculated two levels before ??
                        if (result) {
                            return Q.nfcall(jwt.sign, /* user */ , config.secret, {});
                        } else {
                            return Q.defer().reject(new CError(400, E.INVALID_CREDENTIALS));
                        }
                    })
                    .then(function(token){
                        res.json({token: token});
                    })
                    .catch(function(err){
                        if (err instanceof CError) {
                            res.status(err.status).json({ error : err.message });
                        } else {
                            res.status(500).json({ error : err.toString() });
                        }
                    })
                    .done();

        },

The "problem" I am having right now is that the third then(), the one where I should generate the jwt token I don't have access to user which was calculated two levels above.

How do I overcome this limitation ?

I have some solutions but I don't like them. What is the standard way (if such thing exists) of achieving this ?

Andrei Ciobanu
  • 12,500
  • 24
  • 85
  • 118
  • You seem to only have 1 asynchronous call (the mongoose fetch) - why are you using so many "then" calls? – Amit Jun 15 '16 at 19:25
  • Regarding `return Q.defer().reject(…)`, that should be `return Q.reject(…);` or just `throw …;`. Your first `then` callback shouldn't use any deferreds at all, you can do simply `if (user) return user; else throw new CError(…);`. And you can merge it with your second callback by just putting the `bcrypt.compare` call in place of the `return user` in the first callback. – Bergi Jun 15 '16 at 19:28
  • bcrypt.compare and jwt.sign are also async. – Andrei Ciobanu Jun 15 '16 at 20:08
  • @Bergi I don't quite get it. bcrypt.compare is async. I don't think I can return it as you said. – Andrei Ciobanu Jun 15 '16 at 20:38
  • @AndreiCiobanu: You can (should) put the `return Q.nfcall(bcrypt.compare(…))` call in place of the `defer.resolve(user);` – Bergi Jun 15 '16 at 20:59

1 Answers1

0

I make a temp variable to store them.. not sure if this is the correct way but it's been working for me perfectly.

 //in beginning of your function make the variable
    let _members;

    //promise chain
    .then(members=> {
          //store it in the variable and you can use it later
         _members = members
    }
joe
  • 1,563
  • 4
  • 16
  • 35