Получить доступ

Как в Spring Boot 3 возвращать ошибки REST API в едином формате?

MiddleSpring MVC и RESTSpring BootSpringSpring Boot >=3
Ещё спрашивают так:
  • Что такое 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 с полями ошибок

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Централизация. Класс с @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.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓@RestControllerAdvice с @ExceptionHandler, возвращающими ProblemDetail (RFC 9457); включить spring.mvc.problemdetails.enabled для стандартных исключений
  • ✗Ловить исключения в каждом контроллере try/catch и возвращать строку с текстом ошибки
  • ✗Возвращать стектрейс в теле ответа, чтобы клиент видел причину
  • ✗Всегда возвращать 200 с полем error в теле

Что спросят дальше

  • Что такое ProblemDetail?
  • Как залогировать ошибку, но не отдать её детали клиенту?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем