Promise chaining with mongoDB (and mongoose). How to use .save() after .then() and correctly breakout of a promise chain if a response has been sent? Promise chaining with mongoDB (and mongoose). How to use .save() after .then() and correctly breakout of a promise chain if a response has been sent? mongoose mongoose

Promise chaining with mongoDB (and mongoose). How to use .save() after .then() and correctly breakout of a promise chain if a response has been sent?


You could solve this somehow by chaining promises correctly in a more complicated way, or you use async / await and get rid of all those problems:

router.post('/', async (req, res) => { try {  //Step 1: validae the user input and if there is an error, send 400 res and error message  console.log('My user post body req::', req.body);  const { error } = validateUser(req.body); //this is using Joi.validate() which has a error property if errors are found  if (error) {     return res.status(400).send(error.details[0].message);  }  //step 2: check if user already exists, if yes send res 400  let user = await User.findOne({ email: req.body.email });  if (user) {    return res.status(400).send('User already exists');  }  //Step 3: enter new user into the database  user = new User({            name: req.body.name,            email: req.body.email,            password: req.body.password  });  await user.save();  //step 4: return the newly added user  return res.status(200).send(user); } catch(error) {    // Report error internally    return res.status(500).send("Something bad happened"); } });

The main problem with your code is that returning from a .then callback will continue executing the next .then callback. Therefore you try to set the headers status multiple times (but that's your smallest problem).


You don't need to use Promise.resolve in your route.You just need a chain of then blocks, in which you need to return a value to the next one.

I refactored your code like this:

router.post("/", (req, res) => {    //Step 1: validate the user input and if there is an error, send 400 res and error message    console.log("My user post body req::", req.body);    const { error } = validateUser(req.body);    if (error) {      return res.status(400).send(error.details[0].message);    }    //step 2: check if user already exists, if yes send res 400    User.findOne({ email: req.body.email })      .then(user => {        if (user) {          return res.status(400).send("User already exists");        }        return;      })      .then(() => {        //Step 3: enter new user into the database        let user = new User({          name: req.body.name,          email: req.body.email,          password: req.body.password        });        return user.save();      })      .then(result => {        //step 4: return the newly added user        return res.status(200).send(result);      })      .catch(error => {        console.log("Error Adding new User", error);        res.status(500).send("Error");      });  });

You will have a result like this when a user successfully registers:

{    "_id": "5dd65df52f7f615d8067150d",    "name": "ssaquif",    "email": "test@test.com",    "password": "123123",    "__v": 0}

And when an existing email is used, the response will be like this with statusCode 400.

User already exists


If you look at the error message "Cannot set headers after they are sent to the client" it means you are trying to send something over the response object twice which are not possible. Try log something right before each time you send something as a response and see which two are being called.

Instead of returning the res.status(400).send promise, try call it normally and then return a rejected promise or throw an error instead.