Сегодняшняя статья рассмотрит основные вопросы про REST в Spring. Она будет особенно полезна для начинающих программистов.
Официальный гид от Pivotal, в котором написано про темы для подготовки.
- Внедрение зависимостей, контейнер, IoC, бины
- AOP (аспектно-ориентированное программирование)
- JDBC, транзакции, JPA, Spring Data
- Spring Boot
- Spring MVC
- Spring Security
- REST
- Тестирование
Spring REST — это часть Spring MVC. Поэтому многое из Spring MVC будет применяться в REST и наоборот. Для более подробного ознакомления со Spring MVC можно прочитать эту статью.
Чтобы понять концепцию REST, нужно разобрать акроним на его составляющие:
- Representational — ресурсы в REST могут быть представлены в любой форме — JSON, XML, текст, или даже HTML — зависит от того, какие данные больше подходят потребителю
- State — при работе с REST вы должны быть сконцентрированы на состоянии ресурса, а не на действиях с ресурсом
- Transfer — REST включает себя передачу ресурсных данных, в любой представленной форме, от одного приложения другому.
REST это передача состояний ресурса между сервером и клиентом.
Ресурс в REST — это все, что может быть передано между клиентом и сервером.
Вот несколько примеров ресурсов:
- Новость
- Температура в Санкт-Петербурге в понедельник в 4 утра
- Зарплата сотрудника
- Выборка из базы данных
- Результат поиска
Действия в REST определяются http-методами.
Get
, Post
, Put
, Delete
, Patch
, и другие.
Самые часто-используемые обозначаются аббревиатурой CRUD:
- Create —
POST
- Read —
GET
- Update —
PUT
- Delete —
DELETE
По умолчанию REST не защищен.
Вы можете настроить безопасность с помощью Basic Auth, JWT, OAuth2
Это операции, которые не модифицируют ресурсы. Вот их список:
- GET
- HEAD
- OPTIONS
Идемпотентые методы — это методы, при каждом вызове которых результат будет одинаковый.
То есть, результат после 1 вызова такого метода будет такой же, как и результат после 10 вызовов этого метода.
Это важно для отказоустойчевого API. Предположим, что клиент хочет обновить ресурс с помощью POST-запроса? Если POST не идемпотентный метод, то при многократном вызове возникнут непредвиденные обновления ресурса. Используя идемпотентные методы, вы ограждаете себя от многих ошибок.
Да. REST хорошо масштабируется потому что он не хранит состояние.
Это значит что он не хранит информацию о пользовательских сессиях на сервере.
Информация о клиенте не должна хранится на стороне сервера, а должна передаваться каждый раз туда, где она нужна. Вот что значит ST в REST, State Transfer. Вы передаете состояние, а не храните его на сервере.
REST также интероперабельный — это значит, что на нем могут взаимодействовать разные программы написанные на разных языках. Это исходит из 2ух факторов:
- Интероперабельные HTTP-клиенты. Разные клиенты должны отправлять одинаковые http-запросы.
- Интероперабельность на уровне медиа-типов. Различные клиенты должны корректно отправлять и получать одни и те же ресурсы.
HttpMessageConverter
конвертирует запрос в объект и наоборот.
Spring имеет несколько реализаций этого интерфейса, а вы можете создать свою.
В этом случае DispatcherServlet
не использует Model и View.
В REST вообще не существует Model и View. Есть только данные, поставляемые контроллером, и представление ресурса, когда сообщение конвертируется из медиа-типа(json, xml...) в объект.
Список конвертеров:
BufferedImageHttpMessageConverter
— конвертирует BufferedImage
в(из) код изображения.
Jaxb2RootElementHttpMessageConverter
— конвертирует xml в(из) объект, помеченный jaxb2 аннотациями. Регистрируется, если jaxb2 находится в classpath.
MappingJackson2HttpMessageConverter
— конвертирует JSON в(из) объект. Регистрируется, если Jackson 2 находится в classpath.
StringHttpMessageConverter
— конвертирует все медиа-файлы в text/plain.
@RestController
ставится на класс-контроллер вместо @Controller
. Она указывает, что этот класс оперирует не моделями, а данными. Она состоит из аннотаций @Controller
и @RequestBody
.
@Controller
@ResponseBody
public interface RestController
Аннотация @ResponseBody
ставится на методы, которые работают с данными, а не с моделями. Ее не требуется указывать явно, если используется @RestController
.
Обычные методы возвращают Model
, а методы аннотированные @ResponseBody
возвращают объекты, которые конвертируются в медиа-файлы с помощью HttpMessageConverter
.
Эта аннотация служит для маппинга запросов на классы-контроллеры и методы.
Раньше ее использовали для методов класса, чтобы указать URI, http-метод, тип отправляемых данных, и т.п. В более новых версиях Spring ее заменили на аннотации @GetMapping
, @PostMapping
, и т.п.
Теперь она используется только для указания URI до класса-контроллера.
Это более узкие аннотации для маппинга http-методов.
@GetMapping
— Обрабатывает get-запросы@PostMapping
— Обрабатывает post-запросы@DeleteMapping
— Обрабатывает delete-запросы@PutMapping
— Обрабатывает put-запросы@PatchMapping
— Обрабатывает patch-запросы
Все написанное ниже характерно также и для других аннотаций.
Аннотация @GetMapping — это просто аннотация которая содержит @RequestMapping(method = RequestMethod.GET).
Она также позволяет более глубоко настроить метод-обработчик.
Ее параметры(они конвертируются в аналогичные параметры @RequestMapping):
path
— URIheaders
— заголовкиname
— имя обработчикаparams
— параметрыproduces
— тип возвращаемых данных(JSON, XML, текст). Используется в RESTconsumes
— тип принимаемых данных. Используется в REST
По умолчанию аннотация принимает путь до метода.
@GetMapping("managers") = @GetMapping(path = "managers")
Эта аннотация используется для того, чтобы методы обработчики могли получить параметры из http-запроса.
Запрос с параметрами: http://localhost:8080/getByName/name=Ivan
.
Следующий код поместит в переменную name
строку Ivan
.
@GetMapping("getByName")
public User getUserByName(@RequestParam("name") String name) {
//some logic
}
Эта аннотация получает определенную часть из URI.
URI: http://localhost:8080/getById/23
Следующий код поместит в переменную id
значение 23
.
@GetMapping("getById/{id}") public User getUserById(@PathVariable("id") String id) { //some logic
}
GET — 200 OK
POST — 200 OK, 201 Created, 204 No Content
PUT — 200 OK, 201 Created, 204 No Content
DELETE — 204 No Content, 202 Accepted
Она позволяет устанавливать код ответа. Обычно Spring сам устанавливает нужный код ответа, но бывают моменты, когда это нужно переопределить.
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void add(...) {...}
Вместо использования аннотации можно возвращать ResponseEntity
и вручную устанавливать код ответа.
Не рекомендуется использовать ResponseEntity
и @ReponseStatus
вместе.
Это специальный класс, который представляет http-ответ. Он содержит тело ответа, код состояния, заголовки. Мы можем использовать его для более тонкой настройки http-ответа.
Он является универсальным типом, и можно использовать любой объект в качестве тела:
@GetMapping("/hello")
ResponseEntity hello() {
return new ResponseEntity("Hello World!", HttpStatus.OK);
}
Вы можете использовать аннотацию @RequestBody
на параметре метода, для того чтобы тело запроса конвертировалось в этот параметр.
@PostMapping("accounts")
//Например, запрос с JSON конвертируется в объект Account
public void handle(@RequestBody Account account) {...}
Вы можете использовать @Validated
вместе с @RequestBody
, для проверки пришедшего запроса.
RestTemplate это специальный клиент в Spring для отправки http-запросов. Он предоставляет удобные API для легкого вызова конечных точек REST’а в одну строку.
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl = "http://localhost:8080/spring-rest/foos";
ResponseEntity response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
Более подробно об использовании можно узнать в этой статье.