I'm writing a middleware that has a services layer and a controller layer. In order to transmit a clear error message to the user, I catch any errors in the services layer and then throw a new Error with a personalized message, like this:
// services.js
async getOneRecord(id) {
const url = this.url `/${id}`;
return await axios.get(url).then((res) => res.data);
}
// UserServices.js
async getTaxValue(id) {
try {
const user = await this.getOneRecord(id);
return Number(user.tax) / 100;
} catch (error) {
throw new Error(`User ID not found: ${id}`);
}
}
// UserController.js
static async getUserTax(req, res) {
const { userId } = req.params;
try {
const user = await userServices.getTaxValue(userId);
return res.status(200).json(user);
} catch (error) {
return res.status(404).json(error.message);
}
}
I would like to find out if this is the right way to treat errors or if I'm doing something wrong.
CodePudding user response:
Yes, it's correct and normal to throw
new errors in catch
blocks.
However, it is not a good practice to ignore the error
that you caught. There are a lot of things that can go wrong in getTaxValue
, and I would argue that most of them should not result in an "id not found" error. So be very explicit about the error that you expect, test for it with a condition, and rethrow everything else unchanged. Also set the .cause
of errors.
In your case, that might be (handling only 404 errors from the user record endpoint):
class NotFoundError extends Error {}
async getTaxValue(id) {
try {
const user = await this.getOneRecord(id);
return Number(user.tax) / 100;
} catch (error) {
if (error.response && error.response.status == 404) { // see AxiosError
throw new NotFoundError(`User ID not found: ${id}`, {cause: error});
}
throw error;
}
}
// UserController.js
async function getUserTax(req, res) {
const { userId } = req.params;
try {
const user = await userServices.getTaxValue(userId);
return res.status(200).json(user);
} catch (error) {
return res.status(error instanceof NotFoundError ? 404 : 500).json(error.message);
}
}