Какие основные HTTP методы используются в REST
В архитектурном стиле REST методы сопоставляются с CRUD-операциями над данными:
🟢 Junior Level
HTTP-методы (HTTP Verbs / глаголы HTTP) — это стандартные команды протокола HTTP (спецификация RFC 9110), которые сообщают серверу, какое действие клиент хочет произвести над указанным ресурсом (URI).
В архитектурном стиле REST методы сопоставляются с CRUD-операциями над данными:
| HTTP Метод | CRUD-операция | Назначение | Пример URI | Успешный статус-код |
|---|---|---|---|---|
GET |
Read | Получение представления ресурса (чтение) | GET /api/v1/orders/42 |
200 OK |
POST |
Create | Создание нового дочернего ресурса или вызов действия | POST /api/v1/orders |
201 Created |
PUT |
Update (Replace) | Полная замена ресурса по указанному адресу | PUT /api/v1/orders/42 |
200 OK / 204 No Content |
PATCH |
Update (Partial) | Частичное обновление отдельных полей ресурса | PATCH /api/v1/orders/42 |
200 OK / 204 No Content |
DELETE |
Delete | Удаление указанного ресурса | DELETE /api/v1/orders/42 |
204 No Content |
Пример реализации REST-контроллера на Spring Boot 3
package com.example.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import java.net.URI;
import java.util.List;
@RestController
@RequestMapping("/api/v1/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
// 1. GET: чтение списка или одного элемента
@GetMapping("/{id}")
public ResponseEntity<ProductDto> getProduct(@PathVariable Long id) {
return ResponseEntity.ok(productService.findById(id));
}
// 2. POST: создание ресурса с заголовком Location
@PostMapping
public ResponseEntity<ProductDto> createProduct(@RequestBody CreateProductRequest req) {
ProductDto created = productService.create(req);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(created.id())
.toUri();
return ResponseEntity.created(location).body(created); // 201 Created + Location
}
// 3. PUT: полная замена ресурса
@PutMapping("/{id}")
public ResponseEntity<ProductDto> replaceProduct(@PathVariable Long id,
@RequestBody ReplaceProductRequest req) {
return ResponseEntity.ok(productService.replace(id, req));
}
// 4. PATCH: частичное обновление
@PatchMapping("/{id}")
public ResponseEntity<ProductDto> patchProduct(@PathVariable Long id,
@RequestBody PatchProductRequest req) {
return ResponseEntity.ok(productService.patch(id, req));
}
// 5. DELETE: удаление ресурса
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
productService.delete(id);
return ResponseEntity.noContent().build(); // 204 No Content
}
}
🟡 Middle Level
Классификация методов: Безопасность (Safe) и Идемпотентность (Idempotent)
По спецификации RFC 9110 (HTTP Semantics) все методы разделяются по двум фундаментальным характеристикам:
┌─── Safe (Безопасный: не меняет состояние на сервере): GET, HEAD, OPTIONS, TRACE
┌─── Свойства ┤
│ └─── Idempotent (Идемпотентный: повтор N раз дает тот же итог): GET, HEAD, PUT, DELETE, OPTIONS
HTTP Методы ┤
│ ┌─── PUT: Полная замена (все поля обязательны)
└─── Мутации ┼─── PATCH: Частичное обновление (RFC 6902 / RFC 7386)
└─── POST: Создание / Запуск бизнес-операции (НЕ идемпотентен!)
Сводная матрица свойств методов
| Метод | Наличие тела запроса | Безопасный (Safe)? | Идемпотентный (Idempotent)? | Кэшируемый (Cacheable)? |
|---|---|---|---|---|
GET |
❌ Нет | ✅ Да | ✅ Да | ✅ Да (по умолчанию) |
HEAD |
❌ Нет | ✅ Да | ✅ Да | ✅ Да |
OPTIONS |
❌ Нет | ✅ Да | ✅ Да | ❌ Нет |
POST |
✅ Да | ❌ Нет | ❌ Нет | ⚠️ Только с явным Cache-Control |
PUT |
✅ Да | ❌ Нет | ✅ Да | ❌ Нет |
PATCH |
✅ Да | ❌ Нет | ⚠️ Зависит от операции | ❌ Нет |
DELETE |
⚠️ Не рекомендуется | ❌ Нет | ✅ Да | ❌ Нет |
Вспомогательные методы: HEAD и OPTIONS
HEAD: выполняет точно такой же запрос, какGET, но сервер возвращает только HTTP-заголовки без тела ответа. Применение: проверка размера тяжелого файла (Content-Length) или валидность кэша (ETag,Last-Modified) до начала реальной загрузки.OPTIONS: опрос коммуникационных возможностей сервера. Применение: механизм CORS Preflight в браузерах. Перед отправкой нестандартного запроса браузер шлетOPTIONS, а сервер возвращает разрешенные методы (Access-Control-Allow-Methods: GET, POST, PUT, DELETE) и заголовки.
🔴 Senior Level
Тонкости семантики PUT vs PATCH
- Строгий контракт
PUT(Полная замена):- Если отправлен
PUT /users/42с телом{"name": "Ivan"}, а у пользователя в БД было заполнено полеemail: "ivan@test.com", бэкенд обязан затереть email вnull, посколькуPUTзамещает ресурс целиком. Если поле требуется сохранить, клиент обязан прислать его заново.
- Если отправлен
- Спецификации
PATCH:- JSON Merge Patch (RFC 7386): клиент шлет только изменяемые поля:
{"email": "new@mail.com"}. Проблема: как отличить «поле не передано (не менять)» от «поле передано какnull(стереть значение)»? В Spring Boot это решается через модульorg.openapitools.jackson.nullable.JsonNullable<T>. - JSON Patch (RFC 6902): отправляется декларативный массив атомарных операций (
add,remove,replace,copy,move,test):[ { "op": "replace", "path": "/email", "value": "new@mail.com" }, { "op": "remove", "path": "/phoneNumber" } ]
- JSON Merge Patch (RFC 7386): клиент шлет только изменяемые поля:
Автоматические повторы (Retries) в Service Mesh (Envoy / Istio)
В распределенных микросервисных системах знание идемпотентности методов критично при настройке сетевых политик:
- Безопасные ретраи (Safe Retries): При получении ошибки сети (
503 Service Unavailable,Connection Reset) прокси Envoy / Sidecar может автоматически повторить запросыGET,PUT,DELETEбез риска испортить данные. - Опасность повторов для
POST: Автоматический повтор запросаPOSTкатегорически запрещен (риск двойного списания денег со счета или дублирования заказа). Для безопасного повтораPOSTв архитектуру внедряют заголовокIdempotency-Keyс сохранением уникальных ключей в Redis.
Туннелирование методов (X-HTTP-Method-Override)
Некоторые устаревшие корпоративные прокси-серверы, файрволы (WAF) и клиенты блокируют методы PUT, PATCH или DELETE.
- Для обхода ограничений используют туннелирование через
POSTс заголовком:POST /api/v1/orders/42 HTTP/1.1 X-HTTP-Method-Override: DELETE - В Spring Boot поддержка туннелирования включается через бин
HiddenHttpMethodFilter.
🎯 Шпаргалка для интервью
30-секундный ответ
В REST используются 5 базовых методов HTTP (RFC 9110):
GET— чтение ресурса (Safe, Idempotent).POST— создание подчиненного ресурса или триггер действия (Неидемпотентный).PUT— полная замена ресурса по указанному URI (Idempotent).PATCH— частичное обновление полей ресурса (обычно неидемпотентный).DELETE— удаление ресурса (Idempotent).Вспомогательные методы:
HEAD(заголовки без тела для проверки кэша и размера) иOPTIONS(опрос возможностей сервера и CORS Preflight).
4 каверзных вопроса с ответами
-
В чём принципиальное различие между свойствами Safe (Безопасный) и Idempotent (Идемпотентный)? Ответ: Метод является Safe, если он вообще не изменяет состояние данных на сервере (только чтение:
GET,HEAD,OPTIONS). Метод является Idempotent, если его повторные идентичные вызовы приводят к тому же конечному состоянию данных на сервере, что и первый вызов. Например,DELETEне является безопасным (он модифицирует БД), но он идемпотентен (после 1-го или 100-го вызова сущность в БД удалена). -
Если второй вызов
DELETE /users/1возвращает404 Not Found, нарушается ли идемпотентность? Ответ: Нет, не нарушается. Идемпотентность по RFC 9110 определяется конечным состоянием данных на сервере (Resource State), а не статус-кодом HTTP-ответа. После первого и после второго запроса пользователя с ID 1 в системе нет — значит, состояние сервера не изменилось, и метод идемпотентен. - Зачем нужен метод
HEADи когда его используют на практике? Ответ: МетодHEADвозвращает абсолютно идентичные заголовки, что иGET, но с гарантированно пустым телом ответа. Он незаменим для:- Проверки доступности ресурса (
200vs404) без передачи трафика. - Проверки размера файла перед скачиванием через заголовок
Content-Length. - Проверки валидности клиентского кэша через проверку заголовков
ETagилиLast-Modified.
- Проверки доступности ресурса (
- Что произойдет, если в запросе
PUTне передать одно из существующих полей сущности? Ответ: По контрактуPUTпроизводит полную замену ресурса. Сервер обязан затереть непереданное поле вnull(или выставить дефолтное значение). Если клиент хочет обновить только часть полей, не трогая остальные, он обязан использовать методPATCH.
Красные флаги (чего категорически нельзя говорить)
- ❌ «
PUTиPATCHделают одно и то же, это синонимы» —PUTполностью замещает ресурс,PATCHобновляет только указанные поля. - ❌ «
DELETEнеидемпотентен, потому что второй запрос возвращает ошибку 404» — статус ответа может меняться, важно состояние сервера. - ❌ «
GETможно использовать для удаления или изменения записей в базе» — грубое нарушение спецификации Safe Methods. - ❌ «Метод
POSTидемпотентен из коробки» —POSTпринципиально неидемпотентен и безIdempotency-Keyдублирует действия при повторах.