user11253232
user11253232

Reputation:

How do i get the data outside the sequelize query?

In the back-end i have a controller that receives the login data (username and password) from the front-end, validate them and then returns the result response to the front-end. Here is the controller:

/* POST /api/login */
exports.Login = (req, res, next) => {
  const incomingUsername = req.body.username;
  const incomingPassword = req.body.password;

  const result = validation.ValidateLoginData(
    incomingUsername,
    incomingPassword
  );

  /* Validation fails when the validationResult === 0 */
  /* Validation succeeds when the validationResult === 1 */
  if (result.validationResult === 0) {
    res.json({ result: 0, message: result.validationMessage });
  } else if (result.validationResult === 1) {
    res.json({ result: 1, message: result.validationMessage });
  }
};

The ValidateLoginData() function contains the following steps:

  1. Check if the username or password does not exist (undefined)
  2. Check if the username or password is empty string
  3. Check if the user is owner (Special case)
  4. Check if the user exists in the database
  5. Check if the password is correct

I want to keep all the validation logic in the ValidateLoginData() function.

Here is the first scenario:

exports.ValidateLoginData = (incomingUsername, incomingPassword) => {
  /* Check if the username or password does not exist (undefined) */
  /* Check if the username or password is empty string */
  /* Check if the user is owner (Special case) */
  if (incomingUsername === undefined || incomingPassword === undefined) {
    return {
      validationResult: 0,
      validationMessage: "Undefined username or password!",
    };
  } else if (incomingUsername === "" || incomingPassword === "") {
    return {
      validationResult: 0,
      validationMessage: "Empty username or password!",
    };
  } else if (
    incomingUsername === process.env.OWNER_USERNAME &&
    incomingPassword === process.env.OWNER_PASSWORD
  ) {
    return {
      validationResult: 1,
      validationMessage:
        process.env.OWNER_USERNAME + " (Owner) Logged in sucessfully!",
    };
  }

  /* Here is want to return the result of the database query and it should be the
  user data for further validation like this */
  const user = User.findOne({
    where: {
      username: incomingUsername,
    },
  });

  if (user === null) {
    return {
      validationResult: 0,
      validationMessage: "Incorrect username!",
    };
  } else if (user.dataValues.username === incomingUsername) {
    if (user.dataValues.password === incomingPassword) {
      return {
        validationResult: 1,
        validationMessage: "You logged in successfully!",
      };
    }
  }
};

Second scenario:

/* Or if i can place the validation inside the then() and then return
the validation result out of the ValidateLoginData function */
User.findOne({
    where: {
      username: incomingUsername,
    },
  }).then((user) => {
    if (user === null) {
      return {
        validationResult: 0,
        validationMessage: "Incorrect username!",
      };
    } else if (user.dataValues.username === incomingUsername) {
      if (user.dataValues.password === incomingPassword) {
        return {
          validationResult: 1,
          validationMessage: "You logged in successfully!",
        };
      }
    }
  });

Third scenario:

/* Or if i can place the validation for password inside the second
then() i do not want to have nesting as it makes the code
more complicated */
  User.findOne({
    where: {
      username: incomingUsername,
    },
  })
    .then((user) => {
      if (user === null) {
        /* This returns the result outside the ValidateLoginData function */
        return {
          validationResult: 0,
          validationMessage: "Incorrect username!",
        };
      } else if (user.dataValues.username === incomingUsername) {
        /* This returns the user data to the next then() not outside the
        ValidateLoginData function */
        return user;
      }
    })
    .then((user) => {
      if (user.dataValues.password !== incomingPassword) {
        return {
          validationResult: 0,
          validationMessage: "Incorrect Password",
        };
      } else if (user.dataValues.password === incomingPassword) {
        return {
          validationResult: 1,
          validationMessage: "You logged in successfully!",
        };
      }
    });

The goal from this is that i want to:

  1. Place all the validation logic outside the controller and in the validateLoginData function.
  2. Return an object from the validateLoginData function that contains validationResult and validationMessage.
  3. Avoid nesting as much as possible.

Upvotes: 1

Views: 271

Answers (2)

user11253232
user11253232

Reputation:

I made it like this:

/* POST /api/login */
exports.Login = async (req, res, next) => {
  const incomingUsername = req.body.username;
  const incomingPassword = req.body.password;

  const result = await validation.ValidateLoginData(
    incomingUsername,
    incomingPassword
  );

  /* Validation fails when the validationResult === 0 */
  /* Validation succeeds when the validationResult === 1 */
  if (result.validationResult === 0) {
    res.json({ result: 0, message: result.validationMessage });
  } else if (result.validationResult === 1) {
    res.json({ result: 1, message: result.validationMessage });
  }
};
const User = require("../models/UserModel.js");

exports.ValidateLoginData = async (incomingUsername, incomingPassword) => {
  /* Check if the username or password does not exist (undefined) */
  /* Check if the username or password is empty string */
  /* Check if the user is owner (Special case) */
  if (incomingUsername === undefined || incomingPassword === undefined) {
    return {
      validationResult: 0,
      validationMessage: "Undefined username or password!",
    };
  } else if (incomingUsername === "" || incomingPassword === "") {
    return {
      validationResult: 0,
      validationMessage: "Empty username or password!",
    };
  } else if (
    incomingUsername === process.env.OWNER_USERNAME &&
    incomingPassword === process.env.OWNER_PASSWORD
  ) {
    return {
      validationResult: 1,
      validationMessage:
        process.env.OWNER_USERNAME + " (Owner) Logged in sucessfully!",
    };
  }

  /* Get user from database */
  const user = await User.findOne({
    where: {
      username: incomingUsername,
    },
  });

  /* Validate username and password */
  if (user === null) {
    return {
      validationResult: 0,
      validationMessage: "Wrong username!",
    };
  } else if (user.getDataValue("username") === incomingUsername) {
    if (user.getDataValue("password") !== incomingPassword) {
      return {
        validationResult: 0,
        validationMessage: "Wrong Password!",
      };
    } else if (user.getDataValue("password") === incomingPassword) {
      return {
        validationResult: 1,
        validationMessage: incomingUsername + " logged in successfully!",
      };
    }
  }
};

Upvotes: 0

Thibaud
Thibaud

Reputation: 1095

sequelize return a promise, so the variable databaseResult is printed in the console.log before the assignation in the .then()

try this:

let databaseResult = null;
  User.findOne({
    where: {
      username: incomingUsername,
    },
  })
    .then((res) => {
      databaseResult = res;
      console.log(databaseResult);
    })
    .catch((err) => {
      console.log(err);
    });

rest of you code should be in the .then() if you want to be sure that the operation in sequelize appear, else you can use async await like this :

async function myFunct() {
try {
  let databaseResult = await User.findOne({
    where: {
      username: incomingUsername,
    },
  })
} catch(err) {
console.log(err);
}
console.log(databaseResult);
}

by the way using async in function can be tricky because the function will return a promise :P

Upvotes: 0

Related Questions