Ali Raisi
Ali Raisi

Reputation: 41

Mongoose: Defining 404 status for not finding a document doesnt work

I,m learning MongoDB and mongoose and now I have a problem in defining a 404 status for my route handler. Here is the code:

app.get('/users/:id', async (req, res) => {
const _id = req.params.id

try {
    const user = await User.findById(_id)
    if (!user) {
        return res.status(404).send()
    }
    res.send(user)
} catch (error) {
    res.status(500).send()
}

})

Now if I give it an id that doesn't exist, it doesn't give me 404 Not Found status. it only executes the catch block which is not what I want. I would appreciate it if you tell me where I made mistake or tell me a way to get error handling for that. Thanks

Upvotes: 3

Views: 2250

Answers (2)

Akshat Vashisht
Akshat Vashisht

Reputation: 1

You can solve this issue by validating your IDs before entering the try-catch block of your code using mongoose built-in function isValidObjectId()

You can modify your code to be as follows:

app.get('/users/:id', async (req, res) => {
  const _id = req.params.id

  try {
    // ADD THIS CHECK
    if (!mongoose.isValidObjectID(_id){ // This checks allows us to not go into catch block and return appropriate response
      return res.status(404).send()
    }
    const user = await User.findById(_id)
    if (!user) {
      return res.status(404).send()
    }
    res.send(user)
  } catch (error) {
    res.status(500).send()
  }
});

I took reference from these for the same:

Upvotes: 0

Đăng Khoa Đinh
Đăng Khoa Đinh

Reputation: 5411

The problem

As you can see in the log

CastError: Cast to ObjectId failed for value "6082d50a2c89db3164" at path "_id" for model "User"

It means : the value you provide to findById function ("6082d50a2c89db3164") is not a valid ObjectId.Then the catch block is executed.

Suggestion

1. Validate the parameter before query in database

I understand that you're trying to provide some id that doesn't exist in the database to test. But IMHO, there a difference between 2 cases :

  • you provide a valid id, and this id cannot be found in the database. It should return 404 in this case
  • you provide an invalid id in the request, it could be a string like "6082d50a2c89db3164", or even "#Q*&$(#@*" or anything we could imagine. For this case, it could be better if we validate the input (req.params._id) to ensure that the format is valid. The code will be something like this:
app.get('/users/:id', async (req, res) => {
const _id = req.params.id;

// validate params
if(!isValidateObjectId(_id)) { // the function we need to write
   res.status(200).send("Invalid params"); // you can define your status and message
   return;
}

// good params, get user from database
try {
    const user = await User.findById(_id)
    if (!user) {
        return res.status(404).send()
    }
    res.send(user)
} catch (error) {
    res.status(500).send()
}
})

2. Use findOne() method instead of findById

If you want a simpler solution, don't use findById because the function expects a valid ObjectId. We can use findOne() method :

app.get('/users/:id', async (req, res) => {
const _id = req.params.id

try {
    const user = await User.findOne({_id : _id})
    if (!user) {
        return res.status(404).send()
    }
    res.send(user)
} catch (error) {
    res.status(500).send()
}
})

(IMHO, the first solution is better though..)

Some helpful link :

Upvotes: 1

Related Questions