Reputation: 579
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
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
<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>
<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>
<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