📚 Теория: HTTP статусы для REST (раскрыть)
Почему 200 != всегда успех?
API клиенты (SPA, мобильные, интеграции) зависят от статуса. Если вернуть 200 при ошибке, UI не покажет проблему, а мониторинг не заметит инцидент.
⚠️ 4xx для ошибок клиента, 5xx для ошибок сервера.
Как правильно?
Использовать ResponseEntity с нужным статусом, @ResponseStatus на исключениях, ProblemDetail и централизованные хендлеры.
🔐 Автотесты и curl должны видеть корректные статусы.
Клиент спрашивает статус пользователя, которого нет в БД.
Контроллер возвращает ResponseEntity.ok(error) — UI решает, что всё нормально.
Проблема не фиксируется, SLA нарушен, мониторинг молчит.
Как надо: использовать 404 для отсутствующих ресурсов, 409/422 для конфликтов, 500 для неожиданных ошибок. Вводите контракт через OpenAPI и автотесты в Postman/Insomnia.
Контекст
Команда отключила централизованный error handler, чтобы «быстрее» выпустить фичу. Теперь контроллер сам конструирует ответы и случайно возвращает 200 OK с текстом ошибки. Нужно найти строку и описать, как привести API к стандартам.
- Проверь, какие статусы возвращаются при отсутствии пользователя и исключении.
- Предложи использование
ResponseStatusException,ProblemDetail, тестов сMockMvcиcurl -I. - Подумай про observability: логирование статусов, SLO, дашборды.
Сниппет
Code Review
Референс-исправление
Возвращай правильные статусы и не маскируй ошибки. Используй ResponseEntity.status(...) и централизованный handler.
Флаг ревью: FLAG{http-status-basics-review}
@GetMapping("/{id}")
public ResponseEntity<UserStatusDto> getStatus(Long id) {
return statusService.findStatus(id)
.map(status -> ResponseEntity.ok(mapper.toDto(status)))
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
@ExceptionHandler(IllegalStateException.class)
public ResponseEntity<ProblemDetail> illegal(IllegalStateException ex) {
ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.INTERNAL_SERVER_ERROR);
problem.setDetail(ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(problem);
}
Покрой эндпоинты тестами: mockMvc.perform(get(\"/api/v1/users/404\")).andExpect(status().isNotFound()) и добавь `curl --fail --show-error` в runbook.
Проверка флага
После ревью зафиксируй флаг, чтобы дашборд засчитал лабораторию.