Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

247
Views
How can I fix this ES6 promise chain in Express?

I'm starting with Promise chaining and I'm trying some code using express and mongoose in node. This is my code:

const register = (req, res, next) => {
  User.findOne(req.params.email).exec().then(user => {
    if (user) {
      return res.status(409).json({ error: 409 });
    }
    return User.create(req.body);
  }).then(user => {
    const token = jwt.sign({ sub: user._id }, 'test-secret');
    return res.status(200).json({ token });
  }).catch(err => {
    return next(err);
  });
};

This is a simplified code to register a user and send him a token. What I want to do is, first, check if the user is already registered and, if not, register it.

As you can see, the line 6 is wrong I think, because I'm not returning any Promise, so after the line 4, the code continuos executing. I want to avoid the callback hell, how can I accomplish this? Thanks

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

The fact that you're not returning a Promise is not important. Return values from then() and catch() are automatically wrapped in Promise objects.

The problem is that your flow is linear (it follows a straight path), but you are trying to branch so that some parts only run in some cases. You need two execution paths:

const register = (req, res, next) => {
  User.findOne(req.params.email).exec().then(user => {
    if (user) {
      // Path 1 stops here:
      return res.status(409).json({ error: 409 });

    } else {
      // Path 2 continues down this 2nd Promise chain:
      return User.create(req.body).then(user => {
        const token = jwt.sign({ sub: user._id }, 'test-secret');
        return res.status(200).json({ token });
      })
    }

  }).catch(err => {
    // Both paths converge on this error handler
    return next(err);
  });
};

If you want to avoid deep nesting, you have two options:

  1. Encapsulate the different paths into functions, so you can then do something like this:

    if (user) {
      return sendHttpError(res, 409)
    } else {
      return sendNewUser(res, req.body)
    }
    

Perhaps only the sendHttpError function is necessary, and the other possible path can be the main body of your route. This is pretty standard.

  1. Since one of your branches is only dealing with error cases, you can throw an Error and catch it below, or in an error-handling middleware. It would look like this:

    if (user) {
      // This throw will abort execution of everything that follows. By
      // using a custom Error class, you can then handle it appropriately
      // in a catch() handler or Express middleware:
      throw new APIError(409)
    }
    
    // ... create user and proceed normally
    

This is also a very common pattern.

over 4 years ago · Santiago Trujillo Report

0

Just throw an error if the user already exists to go directly to the catch function.

const register = (req, res, next) => {
  User.findOne(req.params.email).exec().then(user => {
    if (user) {
      throw new Error({ error: 409, msg: 'User already exists' });
    }
    return User.create(req.body);
  }).then(user => {
    const token = jwt.sign({ sub: user._id }, 'test-secret');
    return res.status(200).json({ token });
  }).catch(err => {
    return next(err);
  });
};
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!