Как в Spring Boot 3 возвращать ошибки REST API в едином формате?
- Что такое ProblemDetail?
- Как централизованно обрабатывать исключения в REST API?
@RestControllerAdvice с @ExceptionHandler централизует обработку, а ответ — ProblemDetail (стандарт RFC 9457, application/problem+json): type, title, status, detail, instance и свои поля.
- Spring 6 / Boot 3:
ProblemDetailиErrorResponseиз коробки spring.mvc.problemdetails.enabled=true— стандартные исключения MVC в этом формате- Наружу — понятный код ошибки и correlation id, без стектрейса
А ещё Валидация: MethodArgumentNotValidException → 400 с полями ошибок
Подробно
Централизация. Класс с @RestControllerAdvice содержит методы @ExceptionHandler(OrderNotFoundException.class) и применяется ко всем контроллерам: маппинг исключений на HTTP-ответы в одном месте, без try/catch в каждом методе.
Единый формат — ProblemDetail. RFC 9457 (ранее 7807) описывает тело ошибки: type (URI типа проблемы), title, status, detail, instance и расширения. Spring Framework 6 добавил класс ProblemDetail и интерфейс ErrorResponse; ResponseEntityExceptionHandler можно расширить, чтобы стандартные исключения MVC (неверный JSON, неподдерживаемый метод, ошибки валидации) тоже возвращались в этом формате. В Spring Boot — spring.mvc.problemdetails.enabled=true.
Что отдавать:
- правильный статус: 400 — неверный запрос, 404 — нет ресурса, 409 — конфликт состояния, 422 — бизнес-валидация, 500 — неожиданная ошибка;
- машинный код ошибки (
typeили своё полеcode) для клиентов; - ошибки полей валидации списком;
- trace/correlation id для поддержки;
- никаких стектрейсов и SQL — их в лог.
Пример
@RestControllerAdvice
class ApiErrors {
@ExceptionHandler(OrderNotFoundException.class)
ProblemDetail notFound(OrderNotFoundException e) {
ProblemDetail pd = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, e.getMessage());
pd.setType(URI.create("https://api.shop.ru/errors/order-not-found"));
pd.setProperty("orderId", e.orderId());
return pd;
}
}Что хотят услышать
- @RestControllerAdvice и @ExceptionHandler.
- ProblemDetail и RFC 9457 в Spring 6 / Boot 3.
- Правильные статусы и что нельзя отдавать наружу.
Частые ошибки
- Отдавать стектрейс клиенту.
- Возвращать 200 с полем error.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Ловить исключения в каждом контроллере через try/catch и возвращать строку с текстом ошибки
- ✓@RestControllerAdvice с @ExceptionHandler, возвращающими ProblemDetail (RFC 9457)
- ✗Возвращать стектрейс в теле ответа, чтобы клиент видел причину
- ✗Всегда возвращать 200 с полем error в теле
Что спросят дальше
- Что такое ProblemDetail?
- Как залогировать ошибку, но не отдать её детали клиенту?
Разбор темы
- REST API: статусы, согласование и семантика
Ресурсы и HTTP-глаголы, статус-коды как контракт, content negotiation и message converters, идемпотентность и версионирование.
Связанные вопросы
- Чем @ControllerAdvice отличается от @ExceptionHandler внутри контроллера? Middle
- В контроллере стоит @Valid @RequestBody CreateUserRequest, и клиент прислал невалидное тело. Что произойдёт по умолчанию? Middle
- Какие меры безопасности вы заложите при проектировании публичного REST API с личным кабинетом пользователя? Middle
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.