1

i'm trying on my API to set follow and unfollow function like social medias.

here is my user.controller.js follow function :

 module.exports.follow = async (req, res) => {
 if (!ObjectId.isValid(req.params.id))
 return res.status(400).send('ID unknown :' + req.params.id)

 try {
 // add to the friends list
 await User.findByIdAndUpdate(
  req.params.id,
  { $addToSet: { following: req.body.idToFollow } },
  { $push: { following: req.body.followerId } },
  (err, docs) => {
    if (!err) res.status(201).json(docs);
    else return res.status(400).jsos(err);
  }
 );
// add to friend list
 await User.findByIdAndUpdate(
  req.body.idToFollow,
  { $addToSet: { followers: req.params.id}},
  { new: true, upsert: true },
  (err, docs) => {
    // if (!err) res.status(201).json(docs);
    if (err) return res.status(400).jsos(err);
  }
)

}catch (err) {
  return res.status(500).json({ message: err });
}
};

When i try to "idToFollow" by entering real Id in my mongoDB i have this error :

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I know this error come from my errors calls, but i don't know how to update my code. All my tries ends to broke.

Ps* I'm new in MEAN stack world :)

damian
  • 49
  • 5
  • just catch on error `following: req.body.followerId` instead of `idToFollow` – damian Oct 31 '22 at 01:56
  • 1
    You're calling `res.status(num).json(thing)` (and `jsos`) multiple times because you're calling `User.findByIdAndUpdate` multiple times and sending responses in the callback to that function. That's what's causing that error. You should only do that `res.status` work once. – klhr Oct 31 '22 at 02:39
  • This is unrelated to your question, but the way that you're mixing callback code (`(err) =>...`) and `async/await` looks incorrect. You should either use all callbacks or all async/await (I'd use all async/await). You can use [util/promisify](https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original) to turn callback functions into async/await compatible promise functions. – klhr Oct 31 '22 at 02:41

1 Answers1

1

You are mixing callbacks and Promises. Your await does not have any effect, since mongoose is using the callback function and therefore does not return a Promise. You should simply remove the callback function and handle your code in a "synchronous" way by using await:

module.exports.follow = async (req, res) => {
  if (!ObjectId.isValid(req.params.id))
    return res.status(400).send('ID unknown :' + req.params.id)

  try {
    // add to the friends list
    await User.findByIdAndUpdate(
      req.params.id,
      { $addToSet: { following: req.body.idToFollow } },
      { $push: { following: req.body.followerId } }
    );

    // add to friend list
    await User.findByIdAndUpdate(
      req.body.idToFollow,
      { $addToSet: { followers: req.params.id}},
      { new: true, upsert: true },
    )
    return res.status(201).json(docs);

  } catch (err) {
    return res.status(500).json({ message: err });
  }
};

Notes:

  • You are handling 2 different database operations here. You should definitely spend some time to think about what happens if one of these fail. If the first one fails, you will not have any issue, but if the second one fails you probably want to do some kind of rollback.
  • You can also parallelize both database operations by using Promise.all.
  • If you want to handle failing operations independently, you can just wrap each of it in a try-catch-block
Fabian Strathaus
  • 3,192
  • 1
  • 4
  • 26
  • 1
    thank you so much for explaining what was the issue there Fabian. i will keep this precious advices for my notes. – damian Oct 31 '22 at 11:30