Тип возврата контроллера и лучшие практики httpStatus, а также метод производства/потребления в REST WS

Я начинаю в REST, и у меня есть несколько вопросов:

  • Какой тип должен возвращать контроллер? Как правило, я спрашиваю, должен ли мой Rest @Controller возвращать объект Item как есть или инкапсулировать его в ResponseEntity, чтобы указать http-status-code.
  • Какой код состояния http использовать в методе GET для определенного элемента ("/items/2"), если данный элемент не существует: HttpMediaStatus.OK(200) и нулевой возврат или HttpStatus.NO_CONTENT(204) и нулевой возврат?

Вторая часть: я видел, что можно указать @Produces и @Consumes в методе WS, но какой в ​​этом смысл? Мое приложение и мои методы работают так, зачем указывать MediaType.APPLICATION_JSON_VALUE? Разве Spring/SpringBoot не конвертирует автоматически Item или ResponseEntity в json?

Контекст: использование Spring Boot, спящего режима, веб-сервиса REST.

Спасибо.


person Danton    schedule 05.02.2018    source источник


Ответы (1)


Много вопросов в одном, я приведу краткие ответы с кучей ссылок на соответствующие статьи и справочную документацию.

Какой тип должен возвращать контроллер?

Зависит от вашей аннотации и RESTful-ness вашего сервиса. Есть три аннотации, которые вы можете использовать для контроллеры: @Controller, @RestController и @RepositoryRestController.

Контроллер базовая аннотация, чтобы пометить ваш класс как контроллер. Тип возвращаемого значения методов конечной точки контроллера может быть разным, я приглашаю вас прочитать этот специальный пост, чтобы получить представление о Это. При разработке службы REST вы сосредоточитесь на использовании RestController и RepositoryRestController. RestControlleris Controller + тело ответа. Он связывает возвращаемое значение метода конечной точки с телом веб-ответа:

@RestController
public ItemController {

    @RequestMapping("/items/{id}")
    public Item getItem(@PathVariable("id") String id) {
         Item item = ...

         return item;
    }

}

При этом, когда вы нажимаете http:/.../api/items/foo, Spring делает свое волшебство, автоматически преобразовывая элемент в ResponseEntity с соответствующим кодом состояния 40X и некоторыми заголовками HTTP по умолчанию.

В какой-то момент вам понадобится больше контроля над кодом состояния и заголовками, но при этом вы сможете воспользоваться настройками Spring Data REST. Вот когда вы будете использовать RepositoryRestController с ResponseEntity<Item> в качестве возвращаемого типа, см. пример ссылка Spring Data REST.

Какой код состояния http использовать в методе GET для определенного элемента, если данный элемент не существует?

Прямо сказано: используйте HttpStatus. НЕ НАЙДЕНО. Вы ищете несуществующий ресурс, там что-то не так.

При этом вам решать, как обращаться с отсутствующими ресурсами в вашем проекте. Если ваш рабочий процесс оправдывает это, отсутствующий ресурс может быть чем-то вполне приемлемым, что действительно возвращает 20-кратный ответ, хотя вы можете ожидать, что пользователи вашего API запутаются, если вы не предупредите их или не предоставите какую-либо документацию (мы люди привычек и конвенции). Но я бы все же начал с кода состояния 404.

(...) @Produces и @Consumes по методу WS, но какая от этого польза? Мое приложение и мои методы работают так, зачем указывать MediaType.APPLICATION_JSON_VALUE? Разве Spring/SpringBoot не конвертирует Item или ResponseEntity автоматически в json?

@Consumes и @Produces соответственно сопоставляются с заголовками content-type и accept из запроса. Это средство ограничения принимаемых входных данных и выходных данных, предоставляемых вашим методом конечной точки.

Поскольку мы говорим о службе REST, ожидается, что связь между клиентами API и службой будет в формате JSON. Благодаря Spring HATEOAS ответ фактически отформатирован с типом содержимого application/hal+json. В этом случае вы действительно можете не беспокоиться об этих двух аннотациях. Они понадобятся вам, если вы разрабатываете сервис, который принимает различные типы контента (приложение/текст, приложение/json, приложение/xml...) и предоставляет, например, HTML-представления пользователям вашего веб-сайта и JSON или XML-ответ на автоматические клиенты вашего сервиса.

Для примеров из жизни:

  • Facebook предоставляет Graph API, чтобы приложения могли читать/записывать его граф, в то время как пользователи с удовольствием (?) просматривают веб-страницы
  • Google делает то же самое с API Карт Google.
person Marc Tarin    schedule 05.02.2018
comment
Большое спасибо за ваш очень полный ответ, я буду размышлять над всем этим контентом, но я уже думаю остаться на @RestController, если он волшебным образом использует стандартный код HttpStatus в соответствии с возвращаемым содержимым, как вы сказали (даже если мне нужно действительно понимать конкретные различия с @RepositoryRestController не знал). - person Danton; 05.02.2018
comment
И нет связи с предыдущим вопросом, но все еще в передаче субъекта данных: есть ли какие-либо рекомендации по использованию примитивного или объектного типа при передаче данных? Должен ли мой идентификатор товара быть длинным или длинным или только в соответствии с моими потребностями? - person Danton; 05.02.2018
comment
Вы должны попробовать обе аннотации, и вы быстро увидите различия (и, возможно, у вас возникнут дополнительные вопросы). - person Marc Tarin; 05.02.2018
comment
Как правило, в параметрах запроса используйте типы-оболочки. Они могут принимать значения NULL, что удобно для необязательных параметров запроса. Это объекты, поэтому их можно использовать в коллекциях и, следовательно, в любой реализации списка, которая имеет чрезвычайно полезный API. Главный недостаток заключается в том, что они добавляют накладные расходы, являясь оболочкой для примитивных типов. Если вы не обрабатываете очень большое количество данных в своих запросах, это не должно быть критическим с точки зрения производительности. Это стоит отдельного вопроса, который заслуживает гораздо более подробного ответа. - person Marc Tarin; 05.02.2018
comment
Хорошо, согласно этот пост, @RepositoryRestController должен позволять работать без сервисного слоя, потому что с необходимой логикой можно мгновенно использовать CRUDRepo. Продолжая с @RestController, знаете ли вы, как реализовать метод PATCH (частичное обновление), я не вижу, как обойтись без получения существующего элемента и установки свойств вручную, а затем сохранения с помощью CRUDRepositoey? - person Danton; 05.02.2018
comment
Хм, не так уж и волшебно, он возвращает 200, когда возвращаемый результат равен нулю, но разрешается добавлением HttpServletResponse response в параметр и установкой кода ответа для пользовательского кода: @GetMapping(path = "/{itemNum}") public ItemDTO retrieveItem(@PathVariable Long itemNum, HttpServletResponse response) { ` ItemDTO item = itemService.retrieveItem(itemNum);` ` if(item == null ) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); } возвращаемый элемент;` } - person Danton; 05.02.2018
comment
Вы действительно хотите реализовать PATCH вручную? Пока вы расширяете CrudRepository (или любого потомка), Spring Data REST автоматически предоставляет вам конечные точки RESTful для запросов GET/POST/PUT/PATCH/DELETE/OPTIONS/HEAD. Это выполнимо, но PATCH может быть немного сложным. Это стоит отдельного вопроса (который уже задавался здесь и там, вы уже должны найти полезные ответы на StackOverflow). - person Marc Tarin; 05.02.2018
comment
Пожалуйста, не оставляйте код в комментариях. Вам лучше создать новый вопрос и указать свою проблему и пример кода. Вы получите лучшую видимость и ответы :) - person Marc Tarin; 05.02.2018