API Error Handling
API error handling designs consistent, machine-readable responses that clients can reliably interpret and handle. A good error contract makes failures predictable by defining status codes, stable error identifiers, useful details, and consistent response structure.
An API error contract defines what clients receive when a request cannot be completed successfully. The HTTP status code communicates the broad class of failure, while the response body can provide a stable application-level error code, human-readable message, and optional structured details.
Use HTTP semantics consistently. For example, `400 Bad Request` commonly represents invalid request input, `401 Unauthorized` indicates missing or invalid authentication credentials, `403 Forbidden` indicates that the server understood the request but will not authorize it, and `404 Not Found` indicates that the requested resource cannot be found. `409 Conflict` is useful when the request conflicts with the current resource state, while `422 Unprocessable Content` can represent semantically invalid input when that distinction is useful to the API.
The body should be designed for machines first and humans second. A stable `code` such as `EMAIL_ALREADY_USED` is safer for client logic than matching the text of `message`. Optional fields such as `field`, `details`, or a correlation identifier can provide additional context without forcing clients to parse prose.
In a Java backend, centralize error translation rather than building response bodies independently in every controller. In Spring-based applications, `@RestControllerAdvice` with `@ExceptionHandler` methods is a common approach: domain exceptions are translated into the API's error representation at one boundary.
Do not expose internal exception messages, stack traces, SQL errors, or infrastructure details to external clients. Log diagnostic information on the server with an appropriate correlation identifier, while returning only information that the client needs to understand or recover from the failure.
Key points
- Use HTTP status codes for broad failure semantics and stable application error codes for client-specific handling.
- Keep error response shapes consistent across endpoints.
- Clients should branch on stable machine-readable codes, not human-readable messages.
- Centralize exception-to-response mapping in the backend.
- Return safe diagnostic context to clients and keep sensitive implementation details in server logs.
Interview questions
Why should an API return an application error code instead of making clients inspect the error message?
Human-readable messages can change because of wording, localization, or product requirements. A stable application code gives clients a predictable value for branching and recovery logic. The message can then remain optimized for people without becoming part of the API's programmatic contract.
How would you design a consistent error response for a REST API?
I would define a standard envelope containing at least a stable `code` and human-readable `message`, with optional structured details for validation or domain-specific information. Each endpoint would use HTTP status codes consistently, while application codes would distinguish individual failure conditions. I would document the contract and centralize exception mapping so controllers do not construct ad hoc error responses.
How would you implement centralized API error handling in Spring Boot?
I would use `@RestControllerAdvice` with `@ExceptionHandler` methods to translate known exceptions into a common error DTO. Domain exceptions can map to application-specific codes and HTTP statuses, while unexpected exceptions should produce a generic server-error response. The detailed exception should be logged server-side with a correlation identifier rather than exposed to the client.
How should an API distinguish 401, 403, 404, and 409?
`401` is used when authentication credentials are missing or invalid, while `403` indicates that the request is understood but authorization does not permit the operation. `404` represents a resource that cannot be found, although some systems intentionally use it to avoid revealing whether a protected resource exists. `409` communicates a conflict with the current resource state, such as attempting to create a resource that violates an existing uniqueness constraint.
What should an API do with unexpected exceptions?
The API should convert unexpected failures into a controlled server-error response rather than exposing implementation details. The server should log the exception with enough context to diagnose it, ideally using a correlation or trace identifier that can connect the client-visible failure to backend logs. The response should avoid stack traces, database messages, credentials, and other sensitive information. Monitoring and alerting should detect recurring unexpected failures independently of the client response.