Map Internal Errors to Typed API Errors
Define an error taxonomy, convert thrown domain errors to stable codes and HTTP statuses, and log the internal cause without exposing it to clients.
Task
Create a central error mapper that turns exceptions into consistent, client-safe API errors.
When to use this
Every handler invents its own status code and message, so clients cannot tell a conflict from a validation error and internal details leak.
Prerequisites
- A base error class or error codes module
- A central error middleware
Steps
1. Define domain error classes carrying a stable code, HTTP status, and safe message.
Expected output: Errors have machine-readable identity.
2. Catch thrown errors centrally and map known types to their status and body.
Expected output: Handlers stay free of response formatting.
3. Map unknown errors to a generic 500 and log the real cause with a reference id.
curl -s https://api.example.com/missing | jq '.error.code'Expected output: Stack traces never reach the client.
4. Return a request reference id so support can find the corresponding log line.
Expected output: Users can report an id instead of a raw message.
Troubleshooting
Problem
New error type unhandled
Solution
Default the mapper to 500 for any error not matching a known class, and add tests for each domain type.
Problem
Messages change and break clients
Solution
Treat error codes as the contract and messages as human-readable text that may change.
Limitations
- A taxonomy only helps if handlers throw domain errors instead of generic ones; adoption must be enforced in review.
- Mapping cannot fix an ambiguous requirement; choosing the right status is still a design decision.
Context
Create a central error mapper that turns exceptions into consistent, client-safe API errors. Every handler invents its own status code and message, so clients cannot tell a conflict from a validation error and internal details leak.
Steps
- Define domain error classes carrying a stable code, HTTP status, and safe message. Expected: Errors have machine-readable identity.
- Catch thrown errors centrally and map known types to their status and body. Expected: Handlers stay free of response formatting.
- Map unknown errors to a generic 500 and log the real cause with a reference id. Expected: Stack traces never reach the client.
- Return a request reference id so support can find the corresponding log line. Expected: Users can report an id instead of a raw message.
class AppError extends Error {
constructor(code, status, message) {
super(message); this.code = code; this.status = status;
}
}
if (err instanceof AppError) send(res, err.status, { error: { code: err.code, message: err.message } });
Verify
- Errors have machine-readable identity.
- Handlers stay free of response formatting.
- Stack traces never reach the client.
- Users can report an id instead of a raw message.
Limits
- A taxonomy only helps if handlers throw domain errors instead of generic ones; adoption must be enforced in review.
- Mapping cannot fix an ambiguous requirement; choosing the right status is still a design decision.