0

I have been working on my first node.js backend and I am trying to refactor the login function, but i am not understanding something about promise chaining and error handling. I am hoping someone can help point out what I am missing here.

I have read about promise chaining and I understand that one catch should be able to handle any error in the chain, but I cant seem to get it to work without having an individual .catch for every .then

Here is my userLogin function.

const loginUser = handleAsync(async (req, res, next) => {
  let userEmail = req.body.email;
  let submittedPassword = req.body.password;

  userLogin(userEmail, submittedPassword)
    .then((userObject) => {
      res.json(userObject);
    })
    .catch((err) => {
      res.status(401).send(err);
      console.log("any error inside userLogin: " + err);
    });
});

async function userLogin(email, submittedPassword) {
  console.log("in user login");
  return new Promise(function (resolve, reject) {
    getUserAccountByEmail(email)
      .then((userAccountResults) => {
        let email = userAccountResults[0].email;
        let storedPassword = userAccountResults[0].password;

        //the user exists check the password
        //the user exists. Now Check password.
        checkUserPassword(submittedPassword, storedPassword)
          .then((passwordIsAMatch) => {
            //The password is a match. Now Generate JWT Token.
            generateJWTToken(email)
              .then((tokens) => {
                //build json object with user information and tokens.
                createUserDataObject(tokens, userAccountResults)
                  .then((userObject) => {
                    //send the user object to the front end.
                    resolve(userObject);
                  })
                  .catch((err) => {
                    reject(err);
                  });
              })
              .catch((err) => {
                reject(err);
              });
          })
          .catch((err) => {
            reject(err);
          });
      })
      .catch((err) => {
        reject(err);
      });
  });
}

And here is one of the functions that is a part of the chain

function getUserAccountByEmail(email) {
  return new Promise(function (resolve, reject) {
    logger.info("Looking up user email");

    const users = User.findAll({
      where: {
        email: email,
      },
      limit: 1,
      attributes: [
        "email",
        "password",
        "userId",
        "stripeConnectAccountId",
        "isStripeAccountSet",
        "stripeCustomerId",
      ],
    })
      .then((userResults) => {
        if (doesUserExist(userResults)) {
          resolve(userResults);
        } else {
          console.log("user doesnt exist in getuseraccount");
          reject("User Email Does Not Exist In Database");
        }
      })
      .catch((error) => {
        console.log("Error Accessing Database: UserAccountByEmail");
        logger.error("Error in getUserAccountByEmail: " + error);
      });
  });
}

Any help would be appreciated. Thanks

  • 1
    Everyone of your nested `fn().then()` needs to be `retrurn fn().then()` so that they are chained into the parent promise. But, this code would be massively simpler using `await` and no nesting. – jfriend00 Oct 16 '22 at 00:04
  • Also, stop wrapping existing promise in `new Promise(...)`. There is no need to use that anti-pattern. Just return the promises you already have. – jfriend00 Oct 16 '22 at 00:13
  • jfriend00 thanks for the response. I took your suggestion using await and it is looking much cleaner. Thank you for the help! – user2415458 Oct 17 '22 at 01:44
  • Is there still an open question? If not, you can post your solution as an answer. If there still are open parts to the question, please clarify what else you need help with. – jfriend00 Oct 17 '22 at 02:02

1 Answers1

0

I took jfriend00 's advice and refactored using await instead of nesting.

async function userLogin(email, submittedPassword) {
  return new Promise(async function (resolve, reject) {
    try {
      //Get User Account Information
      const userAccountResults = await getUserAccountByEmail(email);

      //Password Authentication
      let storedPassword = userAccountResults[0].password;
      const passwordIsAMatch = await checkUserPassword(
        submittedPassword,
        storedPassword
      );

      //Generate JWT Tokens
      const tokens = await generateJWTToken(email);

      //Prepare user data JSON for sending to the frontend.
      const userData = await createUserDataObject(tokens, userAccountResults);
      resolve(userData);
    } catch (error) {
      reject(error);
    }
  });
}