0

I'm trying to use validator and express-validator within a NodeJS/ExpressJS/MongoDB/Mongoose app to confirm a user isn't using an email address that's already been registered. I already have a unique index on the email field, but what I'm trying to do is keep all of my validation in one spot using one method. Thus, my question: validating uniqueness using express-validator.

I've created the schema method to lookup the email address, and it's working. I've created the custom validator, and wired it up in the controller. It is also working. My problem is I don't know how to communicate to the validator in the controller the results of the schema method from the callback.

user.js (the model)

...

/**
 * Check for email addresses already in the collection
 */
 checkEmailDupes: function(req, cb) {
   this.model('User').findOne({email: req}, function (err, user) {
     if (err) {
       return cb(err);
     }
     cb(null, user); // this is passing back the expected result
   });
},

...

users.js (the controller)

...
// The call to the custom validator (shown below)
req.assert('email', 'Email must be unique').checkEmailDupes(user);
...

// Check for email addresses that are already registered
expressValidator.Validator.prototype.checkEmailDupes = function(user) {
  user.checkEmailDupes(this.str, function (err, result) {
    if (err) {
      console.log('An error occurred in checkEmailDupes');
    }
    else {
      console.log('Found a user in checkEmailDupes');
      console.log(result); // this is producing the expected result
    }
  });
  return this.error(this.msg || 'Looks like this email address has already been registered');
  return this;
}

I know the return this.error(this.msg...) needs to go elsewhere. Ideally, I'd throw that into the callback, but when I do that I get

TypeError: Object # has no method 'error'

CrankNPlank
  • 97
  • 2
  • 8
  • hi please can anyone take a look at this similar problem https://stackoverflow.com/questions/54735713/why-does-my-mongoose-validation-callback-return-typeerror-respond-is-not-a-fun?noredirect=1#comment96254202_54735713 – OAOD Feb 17 '19 at 18:27

2 Answers2

0

Try this (what is does is create a partial error function with the scope and first argument already 'filled in'):

expressValidator.Validator.prototype.checkEmailDupes = function(user) {
  var error = this.error.bind(this, this.msg || 'Looks like this email address has already been registered');

  user.checkEmailDupes(this.str, function (err, result) {
    if (err) {
      console.log('An error occurred in checkEmailDupes');
      return error();
    }
    else {
      console.log('Found a user in checkEmailDupes');
      console.log(result); // this is producing the expected result
    }
  });
  return this;
}

However, there might be a bit of an issue here, since user.checkEmailDupes is asynchronous but expressValidator.Validator.prototype.checkEmailDupes isn't. I don't know the inner workings of the validator modules to know if that's a problem or not.

EDIT: perhaps this answer I gave a while back might also be of use. Validating a database constraint using express-validator might not be the best solution.

Community
  • 1
  • 1
robertklep
  • 198,204
  • 35
  • 394
  • 381
  • Thanks for giving this a shot, @robertklep. I tried it (with the exception that I moved `return error();` to the else statement, since that's where the magic needed to happen) but found no joy. After reading the other question you referenced, I decided to abandon this angle, and finally got it worked out by checking the error code returned by mongo and setting an error message based on that. – CrankNPlank Sep 30 '13 at 16:53
0

I was ultimately unable to get this method to work. Thanks to @robertklep and his feedback, I decided to use the error code passed back by mongo (in the case of a non-unique value being found for the email, it's MongoError: E11000 duplicate key error index) and set the error message based on that.

It ultimately looks like the following (in the user controller):

user.save(function(err) {
  if (err) {
    // Instantiate the errors array
    var errors = [];

    // Email address already in DB
    if (err.code == 11000) {
      // Build the error object
      var error = {
        param: 'email',
        msg: 'The email address entered has already been registered',
        value: ''
      };

      // Push the error onto the errors array
      errors.push(error);
    }

    return res.render('users/signup', {
      errors: errors,
      user: user
    });
  }

  ...
CrankNPlank
  • 97
  • 2
  • 8