Husnul Aman
Husnul Aman

Reputation: 579

Ignore catch block if try throws an error

I have a try catch block where I try to find the user and if user is found I throw error inside try block. I am trying to catch only the database error inside the catch block. Now I know when I throw an error from try block it will be caught by catch block and ultimately whatever inside the catch block only will be thrown.

try {
  const exists = await User.findOne({ username });
  
  // if user exists throw this and not go inside catch block
  if (exists) throw new Error('username');
} catch (e) {
  // if database error only throw this
  throw new Error('something went wrong');
}

I tried this approach and it works fine for my use case

try {
  const exists = await User.findOne({ username });

  if (exists) throw new Error('username');
} catch (e) {
  if (e.message === 'username') throw new Error('username exists');
  throw new Error('something went wrong');
}

but I think this is pretty repetitive here and also inside my controller I have to check the message and based on the message I have to send different errors like this

try {
  const user = await userService.createUser(username, password);
  return res.status(201).json(user);

} catch (e) {

  if (e.message === 'username exists') return res.status(409).json(e.message);
  return res.status(500).json(e.message);
}

Is there a way I can get around this and ultimately remove if (e.message === 'username') throw new Error('username exists'); line inside the catch block

PS: Answers that doesn't require me to initiate 'exists' inside global scope first and based on that use multiple try catch blocks are welcome.

Upvotes: 1

Views: 2220

Answers (1)

Nithish
Nithish

Reputation: 6049

How about defining a new method which will throw error when there's a db error or return the user if found.

And we can make use of this in another method for eg., consider createUser and based on the return value we can return the error without handling the error in catch.

const isUserExists = async username => {
  try {
    return await User.findOne({
      username
    });
  } catch (err) {
    throw new Error('something went wrong');
  }
}

const createUser = async username => {
  const isExists = await isUserExists(username)
  if (isExists) {
    throw new Error('username');
  }
  // ...rest of the code 
}

For simplicity, below I have simulated all 3 scenarios

  • DB Error

<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script type="text/babel">
async function isUserExists(username) {
  try {
    return await User.findOne({
      username
    });
  } catch (err) {
    throw new Error('something went wrong');
  }
}

async function createUser(username) {
  const isExists = await isUserExists(username)
  if (isExists) {
    throw new Error('username');
  }
}

createUser("test")
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.error(err);
  })
</script>

  • User found

<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script type="text/babel">
async function isUserExists(username) {
  try {
    return await {};
  } catch (err) {
    throw new Error('something went wrong');
  }
}

async function createUser(username) {
  const isExists = await isUserExists(username)
  if (isExists) {
    throw new Error('username');
  }
}

createUser("test")
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.error(err);
  })
</script>

  • User not found

<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script type="text/babel">
async function isUserExists(username) {
  try {
    return await null;
  } catch (err) {
    throw new Error('something went wrong');
  }
}

async function createUser(username) {
  const isExists = await isUserExists(username)
  if (isExists) {
    throw new Error('username');
  }
  return "Sucessful";
}

createUser("test")
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.error(err);
  })
</script>

Upvotes: 2

Related Questions