Not catching an error is perfectly fine, if it's something that shouldn't happen just let it fall through and cause a 500 so we know to fix it
Most of the time when you catch an error you want to map from an infrastructure error (sql, http, rabbit) to a domain error, note this should be done in the infrastructure layer, the domain shouldn't know about the implementation details
try {
throwyThing();
} catch (err) {
switch err.code {
case "123":
throw new NotFoundError("Some message")
case "456":
throw new ValidationError(err.message)
default:
throw err
}
}
Sometimes you might want to just squash all upstream errors and log all the details This can be useful for third parties where you don't know all the errors that could happen but you do know where you want to map them
Downstream you'll just get a generic Unknown "thing" error but you'll know that means there is an unhandled case
try {
await ACMI.fetchProduct();
} catch (err) {
switch err.code {
case "123":
throw new NotFoundError("Couln't find the product")
default:
logger.error(`Unknown ACMI error code=${err.code}, err=${err}`)
throw new UnknownACMIError("Unknown ACMI error");
}
}
If all you do is catch and throw a new error using the existing message, all you're doing is squashing the stack trace and no value is added
try {
throwyThing();
} catch (err) {
throw new Error(err.message);
}
Logging errors for the most part should only happen at the application boundaries for example the http/graphql logger, you shouldn't need to log and rethrow unless you're debugging
For example in most cases this will result in double logging
try {
throwyThing();
} catch (err) {
logger.error(err.message)
throw err;
}