When building APIs, errors will happen:
A junior backend returns random messages.
A senior backend returns consistent, structured errors across the entire system.
| Goal | Meaning |
|---|---|
| Do NOT expose internal details | No SQL errors in response |
| Have 1 single error format | Consistent across all endpoints |
| Log errors centrally | So we can debug incidents |
| Support custom error types | Validation errors, business rule errors |
| Gracefully fail transactions | No corrupted data |
All errors returned to frontend should match this:
{
"success": false,
"message": "Human friendly readable message",
"code": "SOME_ERROR_CODE" // optional, good for apps
}
src/utils/AppError.jsexport default class AppError extends Error {
constructor(message, statusCode = 400, code = "APP_ERROR") {
super(message);
this.statusCode = statusCode;
this.code = code;
Error.captureStackTrace(this, this.constructor);
}
}
This allows throwing errors like:
throw new AppError("Invalid email format", 400, "INVALID_EMAIL");