Вы заметите, что аннотация @RequestMapping также устанавливает атрибут produces. Это указывает, что любой из методов-обработчиков в DesignTacoController будет обрабатывать запросы только в том случае, если заголовок Accept запроса включает в себя «application/json». Это не только ограничивает ваш API только выдачей результатов в виде JSON, но также позволяет другому контроллеру (возможно, DesignTacoController из главы 2) обрабатывать запросы с одинаковыми путями, если эти запросы не имеют требований к вывода в формате JSON. Несмотря на то, что это ограничивает ваш API-интерфейс только JSON (что подходит для ваших нужд), вы можете установить produces как массив String нескольких типов контента. Например, чтобы разрешить вывод XML, вы можете добавить” text/html " в атрибут produces:
@RequestMapping(path="/design", produces={"application/json", "text/xml"})
То что еще вы, возможно, заметили в листинге 6.2, это то, что класс аннотирован @CrossOrigin. Поскольку Angular-часть приложения будет работать на отдельном хосте и/или порту по API (по крайней мере, на данный момент), веб-браузер не позволит вашему Angular-клиенту использовать API. Это ограничение можно обойти, включив заголовки CORS (Cross-Origin Resource Sharing) в ответы сервера. Spring упрощает применение CORS с аннотацией @CrossOrigin. В данном случае @CrossOrigin позволяет клиентам из любого домена использовать API.
Логика в методе recentTacos() довольно проста. Он создает объект PageRequest, который указывает, что вы хотите получить первую (0-я) страницу с первыми 12 результатами сортировки в порядке убывания по дате создания тако. Короче говоря, вы хотите дюжину самых последних созданных дизайнов тако. PageRequest передается в вызов метода findAll() объекта TacoRepository, и содержимое этой страницы результатов возвращается клиенту (ответ, как вы видели в листинге 6.1, будет использоваться в качестве данных модели для отображения пользователю).
Теперь предположим, что вы хотите создать endpoint, который извлекает один тако по его идентификатору. Используя переменную-заполнитель в пути метода обработчика и принимая переменную path, вы можете получить ID и использовать его для поиска объекта Taco используя репозиторий:
@GetMapping("/{id}")
public Taco tacoById(@PathVariable("id") Long id) {
Optional<Taco> optTaco = tacoRepo.findById(id);
if (optTaco.isPresent()) {
return optTaco.get();
}
return null;
}
Поскольку базовый (корневой) путь контроллера - /design, этот метод контроллера обрабатывает запросы GET для /design/{id}, где часть пути {id} является заполнителем. Фактическое значение в запросе задается параметру id, который сопоставляется с заполнителем {id} с помощью @PathVariable.
Внутри tacoById () параметр id передается методу findById() в репозиторий для получения Taco. findById() возвращает Optional<Taco>, потому что возможна ситуация, что нет тако с переданным ID. Поэтому перед тем как получить результат необходимо проверить, существует ли тако по переданному идентификатору. Если такой тако существует, вы вызываете метод get() для Optional<Taco>, чтобы получить Taco.
Если идентификатор не соответствует ни одному известному tacos, вы возвращаете null. Однако это далеко не идеально. Возвращая значение null, клиент получает ответ с пустым телом и кодом состояния HTTP 200 (OK). Клиент получает ответ, который он не может использовать, но код состояния указывает, что все в порядке. Лучшим подходом было бы вернуть ответ со статусом HTTP 404 (не найден).
Текущая реализация не имеет простого способа, чтобы возвращать код статуса 404 от tacoById(). Но если произвести небольшие изменения, это станет возможным:
@GetMapping("/{id}")
public ResponseEntity<Taco> tacoById(@PathVariable("id") Long id) {
Optional<Taco> optTaco = tacoRepo.findById(id);
if (optTaco.isPresent()) {
return new ResponseEntity<>(optTaco.get(), HttpStatus.OK);
}
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
Теперь вместо возврата объекта Taco функция tacoById () возвращает ResponseEntity <Taco>. Если тако найдено, вы оборачиваете объект Taco в ResponseEntity с HTTP-статусом OK (что и было ранее). Но если тако не найдено, вы добавляете в ResponseEntity значение null вместе с HTTP-статусом NOT FOUND, чтобы указать, что клиент пытается получить тако, которого не существует.
Начало API Taco Cloud для вашего Angular-овского (или любого другого, по вашим предпочтениям) клиента положено. Для тестирования разработки вы также можете использовать утилиты командной строки, такие как curl или HTTPie (https://httpie.org/) чтобы лучше понимать API. Например, следующая командная строка показывает, как вы могли бы получить недавно созданные тако с curclass="underline"
$ curl localhost:8080/design/recent
Или такой командой, если вы предпочитаете HTTPie:
$ http :8080/design/recent
Но реализация endpoint, которая возвращает информацию, - это только начало. Что делать, если ваш API должен получать данные от клиента? Давайте посмотрим, как вы можете написать методы контроллера, которые обрабатывают входные данные запросов.