0

Hope you are all doing fine! I am running with some difficulties when I want to deploy this api. I keep on receiving the message:"UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection" My guess is that I am sending a response twice, but I cannot determine where. Does anyone know what could be going on?

router.post('/add', async (req, res) => {
  const friend = await User.findOne({username:req.body.friend})
  const user = await User.findById(req.body.id)

  if(friend && friend != req.headers.username) {
    user.friends.find((x) => {
      switch(friend.username){
        case user.username:{
          res.status(401).json({
            status: "Failed",
            message: "We are sorry but you cant add yourself as friend",
            data:null
        
          })
        }

        case x.friend_username: {
          res.status(401).json({
            status: "Error",
            message: `Sorry, your friend has been already added`,
            data: []
          })
        }

        default: {
          User.findByIdAndUpdate(req.body.id, {
            $addToSet:{
              friends: {
                friend_id: friend.id,
                friend_username: friend.username
              }
            }
          }, {
            upsert: true,
            safe: true
          })  
            .then(result => {
              res.status(200).json({
                status: "Success",
                message: `Friend has been added correctly! `,
                data: result
              })
            })   
            .catch((err)=>{
              res.status(500).json({
                status: "Failed",
                message: "Database Error",
                data: err
              })
            })
          }
        }  
     })
   } else {
     res.status(404).json({
       status: "Failed",
       message: "We are sorry but the username was not found",
       data:null
     })
     console.log(`There has been an failed attempt of adding a new user. \nUser: ${req.headers.username} `)
  }
})

`

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
  • Are you using `mongoose`? – kennarddh Nov 04 '22 at 17:29
  • There's so much wrong with this it's really hard to tell what the exact problem is: you've got a route handler that's way too long (extract some of the logic into functions) no break statements to prevent switch fall through, shotgun formatting (most of which I fixed for you), etc. etc. That being said the problem is likely that one of your db calls throws or the switch fall through is unintended and causing issues. – Jared Smith Nov 04 '22 at 22:37

2 Answers2

0

Try catch block might help with debugging. And it must be used with async/await to catch unhandled promises. I am assuming that the problem is somewhere within User.findOne() or User.findById(). Ether they are working incorrectly, ether you're passing data in request incorrectly.

router.post('/add', async(req,res)=>{
  try {
        const friend = await User.findOne({username:req.body.friend})
        const user = await User.findById(req.body.id)

        if(friend&&friend!=req.headers.username){

          user.friends.find((x)=>{

            switch(friend.username){
              case user.username:{
                res.status(401).json({
                  status: "Failed",
                  message: "We are sorry but you cant add yourself as friend",
                  data:null

              })
              }
              case x.friend_username:{
                res.status(401).json({
                  status: "Error",
                  message: `Sorry, your friend has been already added`,
                  data: []
                })
              }
              default:{

                User.findByIdAndUpdate(req.body.id,{

                  $addToSet:{friends:{
                    friend_id:friend.id,
                    friend_username:friend.username
                  }}
                    },{upsert:true,safe:true})

                      .then(result=>{
                        res.status(200).json({
                          status: "Success",
                          message: `Friend has been added correctly! `,
                          data: result
                            })
                      })

                    .catch((err)=>{
                      res.status(500).json({
                        status: "Failed",
                        message: "Database Error",
                        data: err
                       })
                      })
                  }
                   }  }
                   )}
         else{
        res.status(404).json({
            status: "Failed",
            message: "We are sorry but the username was not found",
            data:null
        })
        console.log(`There has been an failed attempt of adding a new user. \nUser: ${req.headers.username} `)

      }
      } catch(err) {
      console.log(err);
      }

})
Tony
  • 14
  • 4
0

The combination of find() and switch without breaks is probably at the cause, and certainly scrambles the logic.

There are a few other things in the code that can be improved, also. Here's an edit with the changes described in comments...

router.post('/add',async(req,res)=>{
  // surround the async calls with try/catch
  try {
    const friend = await User.findOne({ username:req.body.friend });
    const user = await User.findById(req.body.id);

    // detect and throw app-level errors. do the express response in the catch
    // get the most basic out of the way first. we need a user and a friend for the rest of the route to work
    if (!user || !friend) {
      throw {
        status: 404,
        json: {
          status: "Failed",
          message: "user id or friend name not found",
          data: null
        } 
      }
    }

    // user adding themself as a friend doesn't need a loop to check
    if (friend.username === user.username) {
      throw {
        status: 401,
        json: {
          status: "Failed",
          message: "We are sorry but you cant add yourself as friend",
          data:null
        }
      }
    }

    // the loop that's needed here is hidden in includes()
    if (user.friends.includes(friend.username)) {
      throw {
        status: 401,
        json: {
          status: "Error",
          message: `Sorry, your friend has been already added`,
          data:null
        }
      }
    }
    // now, all of the errors have been detected and thrown
    // do the upsert with another await and send good status
    const addToSet = {
      $addToSet:{friends:{
        friend_id:friend.id,
        friend_username:friend.username
      }}
    };
    // note we await here (not then) since that's the style chosen above
    const result = await User.findByIdAndUpdate(req.body.id, addToSet,{ upsert:true, safe:true });
    res.status(200).json({
      status: "Success",
      message: `Friend has been added correctly! `,
      data: result
    });
  
  } catch (error) {
    console.log(error);
    res.status(error.status).json(error.json);
  }
}
danh
  • 62,181
  • 10
  • 95
  • 136