REST в Spring: семантика методов HTTP

GET — получение ресурса

  • HTTP verb: GET
  • URL: /api/users/12345
  • Status code of response: 200 OK
@GetMapping("/api/users/{id}")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public void findOne(@PathVariable("id") final Long id) {
    userService.findById(id);
}

GET — получение коллекции ресурсов (постраничное)

  • HTTP verb: GET
  • URL: /api/users?page=0&size=20
  • Status code of response: 200 OK
@GetMapping(value = "/api/users", params = {"page", "size"})
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public List<User> findAllPaginated(@RequestParam("page") final int page, @RequestParam("size") final int size) {
    userService.findPaginated(page, size);
}

CREATE — создание ресурса

  • HTTP verb: POST
  • URL: /api/users
  • Status code of response: 201 Created
@PostMapping("/api/users")
@ResponseStatus(HttpStatus.CREATED)
public void create(@RequestBody @Valid final User user) {
    userService.create(user);
}

UPDATE — обновление ресурса

  • HTTP verb: POST
  • URL: /api/users/12345
  • Status code of response: 200 OK
@PutMapping("/api/users/{id}")
@ResponseStatus(HttpStatus.OK)
public void update(@PathVariable("id") final Long id, @RequestBody final User user) {
     userService.update(user);
}

CREATE vs UPDATE — POST vs PUT

Необходимо понимать и разделять REST от HTTP.
REST это архитектурный подход к работе с сервером как с хранилищем неких ресурсов, в то время как HTTP это просто транспорт — протокол, с помощью которого клиент взаимодействует с сервером. REST может быть реализован поверх различных протоколов, а не только на базе HTTP. Поэтому HTTP-методы (POST, PUT, PATCH, DELETE и другие) семантически относятся именно к HTTP как к транспортному уровню REST.

PUT — идемпотентная операция, т.е. повторные вызовы того же запроса не меняют состояние сервера. Например, один и тот же запрос переименования пользователя всегда приводит к тому, что у пользователя будет заданное в запросе имя и не важно сколько раз мы выполнить этот запрос

POST — не идемпотентная операция, т.е. повторные запросы меняют состояние сервера. Например, создание сущности. Сколько раз будет выполнен запрос POST, столько и сущностей должно быть создано на сервере.

PUT = replace. Операция PUT семантически равна операции замены данных на сервере.
POST = insert. Операция POST семантически равна операции вставки новых данных на сервере.

PATCH — частичное обновление ресурса

  • HTTP verb: PATCH
  • URL: /api/users/12345
  • Status code of response: 200 OK
@PatchMapping("/api/users/{id}")
@ResponseStatus(HttpStatus.OK)
public void updatePartial(@PathVariable("id") final Long id, @RequestBody final User user) {
     userService.updatePartial(user);
}

Часто разработчики используют запросы PUT для обновления отдельных полей сущности. Однако это семантически неверно, т.к. PUT подразумевает полную замену сущности.

Для частичного обновления сущности на сервере предназначена операция PATCH

DELETE — удаление ресурса

  • HTTP verb: DELETE
  • URL: /api/users/12345
  • Status code of response: 200 OK или 202 Accepted или 204 No Content
@DeleteMapping("/api/users/{id}")
@ResponseStatus(HttpStatus.OK)
public void updatePartial(@PathVariable("id") final Long id) {
     userService.delete(user);
}

DELETE это идемпотентная операция по спецификации HTTP.
Следовательно не важно сколько раз будет отправлен один и тот же запрос на удаление — первый запрос приведёт к удалению ресурса, а последующие уже не изменят состояние сервера. Но это совсем не означает, что сервер будет возвращать одинаковые ответы на первый и на повторные запросы!

Импотентность это про состояние сервера, а не про клиента.

Если метод DELETE успешно выполняется, то возможны следующие коды состояния ответа:

  •  202 (Принято,Accepted) код состояния, если удаление будет успешным но еще не выполнено.
  •  204 (Нет содержимогоNo Content) код ответа, если удаление было выполнено, но тело ответа отсутствует.
  •  200 (OK) код ответа если удаление было выполнено и ответ содержит код и объект описывающий состояние.

Полезные ссылки на документацию