James
James

Reputation: 3815

Mongoose handle validation error in a promise call and Express middleware

I am trying to refactor an Express based simple API code to use promises instead of callbacks. My only challenge is handling Mongoose validation errors (example testing if user exists) and throw this error into the middleware.

I am handling errors through a middleware on index.js:

// Error handling middleware
app.use(function(err, req, res, next){
  res.status(422).send({error: err._message})
});

This is the piece of code which successfully handles all the edge cases except for the existingUser part where the error is thrown into oblivion and is not visible in the response:

router.post('/signup', function(req, res, next) {
  const email = req.body.email;
  const password = req.body.password;

  // Custom error
  if (!email || !password) {
    return res.status(422).send({ error: 'You must provide email and password'});
  }

  User.findOne({ email: email })
  .then(function(existingUser) {
    // If a user with email does exist, return an error
    if (existingUser) {
      // return res.status(422).send({ error: 'Email is in use' });
      throw new Error('User already exists!');
    }

    // If a user with email does NOT exist, create and save user record
    const user = new User({
      email: email,
      password: password
    });

    // save to database
    return user.save()
  })
  .then(function(user) {
    // Respond to request indicating the user was created
    res.json({ token: tokenForUser(user) });
  })
  .catch(next);

Note that I commented out this piece of code because it will throw an error "Can't set headers after they are sent":

return res.status(422).send({ error: 'Email is in use' });

My questions are:

  1. Is the way I handle custom validation errors (such as testing if email or password fields are blank) correct, or there are better ways, since I am not passing these through the error middleware?
  2. How do I handle errors inside promises?

Upvotes: 1

Views: 1250

Answers (1)

jsan
jsan

Reputation: 2824

You can test for username and password inside a new promise:

Promise.resolve().then(()=> {
  if (!email || !password) {
    throw new Error('You must provide email and password');
  }
  return User.findOne({ email: email })
})

Throwing an error inside then function will stop execution and call the first catch attached to the promise. In your case, the next callback with as first argument the trowed error. Imo, you are doing well, it is up to express app send client error appropriately in the correct middleware.

Upvotes: 1

Related Questions