diff --git a/docs/API.md b/docs/API.md index 67d531d..95d2534 100644 --- a/docs/API.md +++ b/docs/API.md @@ -598,7 +598,37 @@ A user-defined category attached to a specific expense list. ## 6. Error Handling -_TODO_ +All errors are returned as JSON. The `GlobalExceptionHandler` (`@RestControllerAdvice`) maps exceptions to HTTP status codes consistently across every endpoint. + +### Error response format + +Most errors: +```json +{ + "error": "Human-readable message" +} +``` + +Validation errors (`400`): +```json +{ + "username": "size must be between 3 and 30", + "googleId": "must not be blank" +} +``` + +### Status code reference + +| HTTP Status | Condition | Source | +|-------------|-----------|--------| +| 400 Bad Request | Input validation failed (missing/invalid fields) | `MethodArgumentNotValidException` via `@Valid` | +| 400 Bad Request | Business rule violation (e.g. expense not in this list) | `IllegalArgumentException` | +| 403 Forbidden | User not registered in the system | `AuthenticatedUserResolver` → `ResponseStatusException(FORBIDDEN)` | +| 403 Forbidden | Ownership check failed (e.g. deleting someone else's list) | `ResponseStatusException(FORBIDDEN)` in controller | +| 404 Not Found | Entity does not exist (user, list, expense) | `ResourceNotFoundException` | +| 409 Conflict | Username already taken | `UsernameAlreadyExistsException` | +| 429 Too Many Requests | Rate limit exceeded | `RateLimitFilter` (returned directly, not via exception handler) | +| 500 Internal Server Error | Unexpected runtime or generic exception | `RuntimeException` / `Exception` — message is hidden from client | ## 7. Recent Changes — `feature/security-hardening`