1

I have a node server, this is the login route. I am trying to send a response after checking if the user exists in the DB and if the password match the hash value. I am using a custom flag but the code where I check for the value is executed before the value can be changed.

router.route('/login').post( (req,res) => {
        User.findOne({email: req.body.email} ,(err,user) => {
            let check = false
            if(!user){
                return res.json({
                    loginSuccess:false,
                    message : "Invalid Email or Password"
                })
            }
            user.comparePassword(req.body.password,(err, isMatch)=> {
                if(err){
                    return res.json({
                        loginSuccess : false,
                        message : "Can't Login. Try Again!"
                    })
                };
                if(isMatch){
                    check = true
                }
            })
    
            if(!check){
                return res.json({
                    loginSuccess : false,
                    message : "Invalid Eail or Password"
                })
            }
            
            user.generateToken((err, user) => {
                if(err) {
                    return res.status(400).send(err)
                }
                else{
                res.cookie('x_auth' , user.token)
                .status(200)
                .json({
                    user : user,
                    loginSuccess:true 
                })
                }
            })
    
        })
    })

In the code above, how can I make

if(!check){
                return res.json({
                    loginSuccess : false,
                    message : "Invalid Eail or Password"
                })
            }

Wait for this:

user.comparePassword(req.body.password,(err, isMatch)=> {
                if(err){
                    return res.json({
                        loginSuccess : false,
                        message : "Can't Login. Try Again!"
                    })
                };
                if(isMatch){
                    check = true
                }
            })

Actually the code below executes first before the flag is changed, but I want it to wait, so it can decide on the new value of check

1

3 Answers 3

1

You want to do your checking inside the callback.

router.route('/login').post((req, res) => {
    User.findOne({ email: req.body.email }, (err, user) => {
        if (!user) {
            return res.json({
                loginSuccess: false,
                message: "Invalid Email or Password"
            })
        }
        user.comparePassword(req.body.password, (err, isMatch) => {
            if (err) {
                return res.json({
                    loginSuccess: false,
                    message: "Can't Login. Try Again!"
                })
            };
            if (!isMatch) {
                return res.json({
                    loginSuccess: false,
                    message: "Invalid Eail or Password"
                })
            }
            user.generateToken((err, user) => {
                if (err) {
                    return res.status(400).send(err)
                }
                else {
                    res.cookie('x_auth', user.token)
                        .status(200)
                        .json({
                            user: user,
                            loginSuccess: true
                        })
                }
            })
        })
    })
})
Sign up to request clarification or add additional context in comments.

Comments

1

You need to convert that callback into promise:

await new Promise((resolve, reject) => {
    user.comparePassword(req.body.password, (err, isMatch)=> {
       if(err){
           return res.json({
               loginSuccess : false,
               message : "Can't Login. Try Again!"
           });
       };
       if(isMatch){
           check = true;
           resolve();
       }
   });
});

Comments

1

You can use Javascript's Promise API, where the executor function would execute your login and the .then and .catch would be executed after the promise's executor, depending on whether it was fulfilled. The documentation provides this example:

let myFirstPromise = new Promise((resolve, reject) => {
  // We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
  // In this example, we use setTimeout(...) to simulate async code. 
  // In reality, you will probably be using something like XHR or an HTML5 API.
  setTimeout( function() {
    resolve("Success!")  // Yay! Everything went well!
  }, 250) 
}) 

myFirstPromise.then((successMessage) => {
  // successMessage is whatever we passed in the resolve(...) function above.
  // It doesn't have to be a string, but if it is only a succeed message, it probably will be.
  console.log("Yay! " + successMessage) 
});

Basically you will need to resolve/reject the promise at the end of your login method. You can also resolve this with callbacks, as Duc Nguyen has already suggested, but in that case beware callback hell.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.