1

So I have a a promise chain that solves a certain callback hell I was experiencing.

Here's what the chain looks like:

server.exchange(oauth2orize.exchange.password(
    function(client, email, password, scope, done) {
        users.findOne({email: email})
            .then(authenticateUser) // mix in password here?
            .then(deleteExistingTokens) 
            .then(createAndSaveNewTokens) 
            .then(function(results){
                done(null, results[0], results[1], {'expires_in': tokenLife});
            }).catch(err => {done(err);});
    }));

So users.findOne returns a promise that returns my user. I need to 'mix in' the password to authenticate against. Given that this is my definition of authenticateUser, how would I go about inserting new variables in the chain?

const authenticateUser = (err, user) => { // add password here?
    return Promise((resolve, reject) => {
        if (!user) {
            reject('User not found');
        } 
        try {
            return User(user).authenticate(password)
            .then((result) => {
                if (result) {
                    resolve(user);
                } else {
                    reject('Invalid password');
                }
            });
        }
        catch (err) {
            reject('Invalid user');
        }
    });
};
Mathieu Bertin
  • 425
  • 5
  • 19

1 Answers1

6

You do that by using an inline function:

.then(value => authenticateUser(value, password)) // mix in password here?

You'll have to update authenticateUser, though, since the signature in your question is an old-style NodeJS callback which doesn't accept a password, not a function meant to be passed into then.

Perhaps something like this (see comments, but also keep reading):

const authenticateUser = (user, password) => {
    // We shouldn't need to create a new promise here, we have one
    // from `authenticate` below we can use
    return Promise((resolve, reject) => {
        if (!user) {                       // This shouldn't be
            reject('User not found');      // necessary...?
        }                                  // ...
        try {
            // No `return` on th enext line, doesn't do anything
            // useful in the Ppromise init callback
            User(user).authenticate(password)
            .then((result) => {
                if (result) {
                    resolve(user);
                } else {
                    reject('Invalid password');
                }
            });
        }
        catch (err) {
            reject('Invalid user');
        }
    });
};

Note that in the above, I've left the logic in the then callback on authenticate alone, but it shouldn't be resolving with null for the user, so your then callback should be able to assume the user is valid (which simplifies the above). authenticate should reject if the authentication fails.

Also note that since authenticate returns a promise, we shouldn't have to create a new one in authenticateUser.

Here's my take at a completely new authenticateUser:

const authenticateUser = (user, password) => {
    // This `try` is only here to guard against possible exceptions
    // from `User` or  `authenticate`
    try {
        return User(user).authenticate(password);
    }
    catch (Exception e) {
        return Promise.reject(e);
    }
};
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I noticed you only have value there. Doesn't the function signature put error in first? – Mathieu Bertin Dec 05 '16 at 18:19
  • @MathieuBertin: No. That's old-style NodeJS callbacks. When using Promises, success and failure take different paths. Resolution is success and it follows the `then` trail (the first function passed to `then`). Rejection is error and it follows the `catch` trail (or the second function passed to `then`). – T.J. Crowder Dec 05 '16 at 18:23