В некоторых ситуациях обработчики должны менять код ответа или добавлять свои заголовки. Сделать это можно с помощью возврата специального объекта ResponseEntity
, который позволяет изменять HTTP-ответ.
Допустим, у нас есть обработчик, возвращающий список страниц Page
. При этом мы хотим добавить заголовок X-Total-Count
, который бы указывал на общее количество страниц:
@SpringBootApplication
@RestController
public class Application {
private List<Page> pages = new ArrayList<Page>();
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@GetMapping("/pages")
public List<Page> index() {
return pages;
}
}
Чтобы это сделать, нам нужно импортировать ResponseEntity
. С его помощью мы соберем ответ и вернем его наружу:
// Остальные импорты
import org.springframework.http.ResponseEntity;
@SpringBootApplication
@RestController
public class Application {
private List<Page> pages = new ArrayList<Page>();
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@GetMapping("/pages")
public ResponseEntity<List<Page>> index(@RequestParam(defaultValue = "10") Integer limit) {
var result = pages.stream().limit(limit).toList();
return ResponseEntity.ok()
.header("X-Total-Count", String.valueOf(pages.size()))
.body(result);
}
@GetMapping("/pages/{id}")
public ResponseEntity<Page> show(@PathVariable String id) {
var page = pages.stream()
.filter(p -> p.getId().equals(id))
.findFirst();
return ResponseEntity.of(page);
}
}
Обсудим этот код подробнее. Здесь ResponseEntity
— это билдер. Его сборка начинается с методов, определяющих код возврата: ok()
соответствует коду 200, created()
— коду 201 и так далее. Дальше можно задавать хедеры и передавать тело ответа.
Использование ResponseEntity
меняет тип возвращаемого значения так, что изначальное значение оборачивается в ResponseEntity
. Это значит, что с его введением придется работать через него целиком. Например, уже не получится просто так вернуть объект с данными, его нужно будет передавать в метод body()
.
В работе ResponseEntity
вам пригодится еще три метода:
status()
, чтобы указать произвольный статусof()
, чтобы работать сOptional
ok()
, который принимает тело ответа и немного укорачивает запись. Это полезно, когда не нужно вызывать дополнительные методы
Самостоятельная работа
На этом шаге мы сделаем наш блог более «правильным» с точки зрения REST: каждый запрос будет возвращать соответствующий HTTP-код. Это важно для взаимодействия с фронтендом и сторонними клиентами.
Повторяем теорию
- Убедитесь, что у вас уже реализован CRUD для постов (
/posts
). - Напомним: HTTP-коды помогают клиентам понимать результат запроса:
200 OK
— успешно получен ресурс201 Created
— ресурс успешно создан204 No Content
— ресурс успешно удалён, тело ответа не возвращается
- Подробности можно посмотреть здесь.
- Убедитесь, что у вас уже реализован CRUD для постов (
Добавляем коды ответа
Добавьте подходящие коды ответа методов
Подсказка
@GetMapping("/posts") public ResponseEntity<List<Post>> getAllPosts() { // 200 } @PostMapping("/posts") public ResponseEntity<Post> createPost(@RequestBody Post post) { Post saved = postService.save(post); // 201 } @DeleteMapping("/posts/{id}") public ResponseEntity<Void> deletePost(@PathVariable Long id) { postService.delete(id); // 204 }
Проверяем работу
- Сделайте несколько запросов через Postman или curl.
- Убедитесь, что при создании поста возвращается
201
, при удалении —204
, при получении —200
.
Дополнительно
- Попробуйте добавить коды для ошибок, например
404 Not Found
, если пост с указанным id не существует. - Сделайте commit и запушьте изменения на GitHub.
- Попробуйте добавить коды для ошибок, например
Итог: теперь ваш CRUD соответствует REST-стандартам и корректно возвращает коды ответа HTTP. Это делает API более предсказуемым и удобным для использования.
Дополнительные материалы
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.