DEV Community

Simone Aronica
Simone Aronica

Posted on • Edited on

Handling async await

I'm trying to implement a register system, and I have to validate the mail and check that it's not already being used by another account in the database. The problem is that the validator function for email must be asynchronous as the query is asynchronous, but the verifyUser function that among other things verifies the email must be a normal function.

To the code!

async function _verifyEmail(User){
    const { email } = User;
    var isAvailable = await UserModel.countDocuments({email: email}).then(res => isAvailable = res > 0 ? false : true);
    var isValid = EmailValidator.validate(email)
    console.log(`isValid: ${isValid}`)
    console.log(`isAvailable: ${isAvailable}`);
    if(!!isValid || !isAvailable)
        return 400;
    else
        return 202;   
}

function _verifyUser(User){
    var emailStatus;
    _verifyEmail(User).then(res => {
        emailStatus = res;
        console.log(`res: ${res}`);
    });

    const passwordStatus = _verifyPassword(User);
    const nameStatus = _verifyName(User);
    const surnameStatus = _verifySurname(User);

    console.log(`email status: ${emailStatus}`);
    console.log(`password status: ${passwordStatus}`);
    console.log(`name status: ${nameStatus}`);
    console.log(`surname status: ${surnameStatus}`);

    if(emailStatus === 400 || passwordStatus === 400 || nameStatus === 400 || surnameStatus === 400)
        return 400;
    else
        return 202;
}

The problem

When I run this code while every other parameter in _verifyUser is fine, emailStatus is unavailable since the _verifyEmail function returns after the if computation.

How can I solve this?

Top comments (6)

Collapse
 
jaakofalltrade profile image
Jaako

I think you can just async await the callback.


_verifyEmail(User).then(async res => {
        emailStatus = await res;
        console.log(`res: ${res}`);
});

Collapse
 
itssimondev profile image
Simone Aronica • Edited

I think you are the most intelligent person in the world.
I'll try this right away! Thanks!

Edit: unfortunately same result, it's still not working for some reason...

Collapse
 
jaakofalltrade profile image
Jaako

I think I have found the problem, you're console logging res instead of emailStatus.

Thread Thread
 
itssimondev profile image
Simone Aronica • Edited

I'm console logging both, but that's not the problem. The problem is that when _verifyEmail ends the result is a promise instead of an actual value.

Edit:
When I execute this code:

function _createUser(userinfo){
    var User = new UserModel(userinfo);
    var status;
    status = _saveUser(User);
    console.log(`_saveUser returned ${status}`);
    if(status === 203)
        return 201;
    return 400;
} 

function _verifyName(User){
    const { name } = User;
    if(!name.match(/[A-Za-z]/g))
        return 400;
    return 202;
}

function _verifySurname(User){
    const { surname } = User;
    if(!surname.match(/[A-Za-z]/g))
        return 400;
    return 202;
}

async function _verifyEmail(User){
    const { email } = User;
    /* const { wellFormed, validDomain, validMailbox } = await validator.verify(email); */
    var isAvailable = await UserModel.countDocuments({email}).
        then(res => {
            isAvailable = res > 0 ? false : true;
            var isValid = EmailValidator.validate(email)
            /* console.log(`wellFormed: ${wellFormed}`);
            console.log(`validDomain: ${validDomain}`);
            console.log(`validMailbox: ${validMailbox}`); */
            console.log(`isValid: ${isValid}`)
            console.log(`isAvailable: ${isAvailable}`);
            if(!!isValid || !isAvailable)
                return 400;
            else
                return 202;  
        });
    return isAvailable;
}

function _verifyPassword(User){
    const { password } = User;
    if(password.lenght < 8 || password.lenght > 24 || !password.match(/[A-Za-z0-9!-/]/g))
        return 400;
    return 202;
}

function _verifyUser(User){
    var emailStatus;
    _verifyEmail(User).then(async res => {
        emailStatus = await res;
        console.log(`res: ${res}`);
    });

    const passwordStatus = _verifyPassword(User);
    const nameStatus = _verifyName(User);
    const surnameStatus = _verifySurname(User);

    console.log(`email status: ${emailStatus}`);
    console.log(`password status: ${passwordStatus}`);
    console.log(`name status: ${nameStatus}`);
    console.log(`surname status: ${surnameStatus}`);

    if(emailStatus === 400 || passwordStatus === 400 || nameStatus === 400 || surnameStatus === 400)
        return 400;
    else
        return 202;
}

function _saveUser(User){
    var status = _verifyUser(User);
    console.log(`_verifyUser returned ${status}`);
    if(status === 400)
        return 400;
    else
    {
        User.save().then(status = 201);
        return status;
    }
}

I get this as a result:

email status: undefined
password status: 202
name status: 202
surname status: 202
_verifyUser returned 202
_saveUser returned 201
isValid: true
isAvailable: false
res: 400

but _verifyUser should be a 400 (look at res) since there is already a user with the mail I've sent.

Thread Thread
 
jaakofalltrade profile image
Jaako • Edited

Ok, the problem is you cannot pass a value to emailStatus coming from the .then method:

I have encountered this problem before but I forgot how I got to the bottom of it.
This post should help.

var emailStatus; // You cannot pass a value here
_verifyEmail(User).then(async res => {
        // Coming from here, the value inside this scope is only contained 
        // inside this scope correct me if I'm wrong.
        emailStatus = await res;
        console.log(`res: ${res}`);
    });

I think there are two ways to solve this problem,

The first one requires you to add an async in _verifyUser:


async function _verifyUser(User){
    var emailStatus = await _verifyEmail(User); // Here
    const passwordStatus = _verifyPassword(User);
    const nameStatus = _verifyName(User);
    const surnameStatus = _verifySurname(User);

    console.log(`email status: ${emailStatus}`);
    console.log(`password status: ${passwordStatus}`);
    console.log(`name status: ${nameStatus}`);
    console.log(`surname status: ${surnameStatus}`);

    if(emailStatus === 400 || passwordStatus === 400 || nameStatus === 400 || surnameStatus === 400)
        return 400;
    else
        return 202;
}

The second one is a little bit experimental because i don't know if it will work:
Edit: Come to think of it this will not work, it will only return a promise I think.

function _verifyUser(User){
    // here
    var emailStatus = _verifyEmail(User).then(async res => {
        return emailStatus = await res;
    });
    const passwordStatus = _verifyPassword(User);
    const nameStatus = _verifyName(User);
    const surnameStatus = _verifySurname(User);

    console.log(`email status: ${emailStatus}`);
    console.log(`password status: ${passwordStatus}`);
    console.log(`name status: ${nameStatus}`);
    console.log(`surname status: ${surnameStatus}`);

    if(emailStatus === 400 || passwordStatus === 400 || nameStatus === 400 || surnameStatus === 400)
        return 400;
    else
        return 202;
}

Collapse
 
itssimondev profile image
Simone Aronica

Because that would require enormous updates in my codebase as this function is contained into a _saveUser function that is contained into a _createUser function that returns to the express router the status code to return to the client through HTTP