Перейти к содержимому

HTTP методы

HTTP методы — глаголы REST для действий над ресурсами. GET (чтение, безопасный, идемпотентный, кешируется). POST (создание или действие, не идемпотентный, ID генерирует сервер). PUT (полная замена ресурса, идемпотентный, клиент знает ID, отсутствующие поля удаляются). PATCH (частичное изменение, не обязан быть идемпотентным). DELETE (удаление, идемпотентный). HEAD (только заголовки), OPTIONS (список методов, для CORS). Типичные ошибки: GET для изменения данных, POST для чтения, PUT для частичного обновления, неправильный статус для POST (нужен 201 Created).

Введение: Глаголы для работы с ресурсами

В предыдущей теме мы говорили о ресурсах — существительных в мире API. Пользователь, заказ, товар. Но чтобы что-то сделать с ресурсом, нужны глаголы.

В REST API глаголы — это HTTP методы. Они говорят серверу, какое действие нужно выполнить с ресурсом: прочитать, создать, изменить, удалить. Всего несколько методов покрывают практически все операции, которые могут понадобиться в API.

HTTP методы — это стандартизированные глаголы протокола HTTP, которые указывают на желаемое действие с ресурсом. Каждый метод имеет своё значение, свои правила и свои свойства (безопасность, идемпотентность).

Правильное использование HTTP методов — это не просто “техническая деталь”. Это способ сделать API понятным, предсказуемым и соответствующим веб-стандартам. Когда разработчик видит DELETE /users/123, он сразу понимает, что произойдёт, даже без документации.

Основные HTTP методы

МетодНазначениеБезопасныйИдемпотентныйЕсть тело запросаЕсть тело ответа
GETПолучить ресурсДаДаНетДа
POSTСоздать ресурс или выполнить действиеНетНетДаДа
PUTПолностью заменить ресурсНетДаДаДа (опционально)
PATCHЧастично изменить ресурсНетНет*ДаДа (опционально)
DELETEУдалить ресурсНетДаОпциональноДа (опционально)
HEADПолучить только заголовкиДаДаНетНет (только заголовки)
OPTIONSПолучить список доступных методовДаДаНетДа

* PATCH не обязан быть идемпотентным, но может быть.

GET: Получение данных

GET — самый простой и самый используемый метод. Он запрашивает представление ресурса. GET никогда не должен изменять данные на сервере.

Получение одного ресурса

GET /users/123
HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 123,
    "name": "Иван",
    "email": "ivan@example.com"
}

Получение коллекции

GET /users
HTTP/1.1 200 OK
Content-Type: application/json

{
    "data": [
        {"id": 1, "name": "Иван"},
        {"id": 2, "name": "Петр"}
    ]
}

GET с параметрами (фильтрация, пагинация, сортировка)

GET /users?status=active&page=2&limit=10&sort=-created_at

Чего нельзя делать с GET

# Плохо! GET не должен изменять данные
GET /users/123/delete
GET /users/123?action=activate
GET /api/charge?amount=100&user=123

Почему: GET должен быть безопасным. Поисковые роботы, браузеры, префетчеры могут случайно вызвать такие URL. Идемпотентность GET гарантирует, что повторные вызовы не навредят, но безопасность требует, чтобы они вообще ничего не меняли.

Кеширование GET

GET ответы могут кешироваться браузером, прокси, CDN.

HTTP/1.1 200 OK
Cache-Control: max-age=300
ETag: "abc123"

{"id": 123, "name": "Иван"}

POST: Создание и действия

POST используется для создания новых ресурсов и для операций, которые не вписываются в стандартные CRUD.

Создание ресурса

POST /users
Content-Type: application/json

{
    "name": "Иван",
    "email": "ivan@example.com"
}
HTTP/1.1 201 Created
Location: /users/123
Content-Type: application/json

{
    "id": 123,
    "name": "Иван",
    "email": "ivan@example.com",
    "created_at": "2024-01-15T10:30:00Z"
}

Важно: POST не идемпотентен. Если отправить один и тот же запрос дважды, могут создаться два ресурса.

Выполнение действий (не-CRUD операции)

POST /users/123/activate
POST /orders/456/pay
POST /emails/send
POST /search   # поиск с телом запроса

Когда POST, а когда PUT

КритерийPOSTPUT
Кто создаёт IDСерверКлиент
URI/users (коллекция)/users/123 (конкретный)
ИдемпотентностьНетДа
ИспользованиеСоздание, действияПолная замена

Как сделать POST идемпотентным

Метод 1: Idempotency-Key (заголовок)

Клиент генерирует уникальный ключ и шлёт в заголовке. Сервер запоминает ключ и результат.

Пример запроса:

POST /payments HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{ "amount": 100, "from": "alice", "to": "bob" }

Логика сервера:

  1. Проверить в БД (или Redis) ключ 550e8400-....
  2. Если ключа нет → выполнить перевод, сохранить результат (например, { "status": "ok", "payment_id": 123 }) под этим ключом.
  3. Если ключ есть → вернуть сохранённый результат, ничего не меняя.

Метод 2: UUID в теле (клиентский ID ресурса)

Клиент сам назначает ID ресурса и включает его в тело запроса.

Пример запроса:

POST /users HTTP/1.1
Content-Type: application/json

{ "user_id": "550e8400-e29b-41d4-a716-446655440000", "name": "Alice" }

Логика сервера:

  1. Проверить, есть ли пользователь с user_id = 550e8400-....
  2. Если нет → создать нового пользователя с этим ID.
  3. Если есть → вернуть существующего (или статус 409 Conflict, в зависимости от дизайна).

PUT: Полная замена ресурса

PUT полностью заменяет ресурс по указанному URI. Если ресурс существует — заменяет. Если нет — создаёт (в некоторых API).

Полная замена ресурса

PUT /users/123
Content-Type: application/json

{
    "name": "Иван Петров",
    "email": "ivan.new@example.com",
    "phone": "+7-999-123-45-67"
}
HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 123,
    "name": "Иван Петров",
    "email": "ivan.new@example.com",
    "phone": "+7-999-123-45-67"
}

Важное свойство: PUT требует полного представления

# Если отправить только имя
PUT /users/123
{"name": "Новое имя"}

# Что произойдёт с email, phone? 
# В правильно реализованном PUT — они будут удалены (заменены на NULL)

Поэтому для частичных обновлений используют PATCH.

PUT для создания (с известным ID)

PUT /users/123
Content-Type: application/json

{
    "name": "Иван",
    "email": "ivan@example.com"
}
HTTP/1.1 201 Created
Location: /users/123

PATCH: Частичное изменение ресурса

PATCH применяет частичные изменения к ресурсу. В отличие от PUT, клиент отправляет только те поля, которые нужно изменить.

Частичное обновление

PATCH /users/123
Content-Type: application/json

{
    "phone": "+7-999-999-99-99"
}
HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 123,
    "name": "Иван",
    "email": "ivan@example.com",
    "phone": "+7-999-999-99-99"
}

JSON Patch (RFC 6902) — стандартный формат для PATCH

PATCH /users/123
Content-Type: application/json-patch+json

[
    { "op": "replace", "path": "/phone", "value": "+7-999-999-99-99" },
    { "op": "add", "path": "/tags/-", "value": "vip" },
    { "op": "remove", "path": "/old_field" }
]

PUT vs PATCH

АспектPUTPATCH
Что отправляет клиентПолное представление ресурсаТолько изменения
Что происходит с отсутствующими полямиУдаляются (или NULL)Остаются без изменений
Когда использоватьПолная заменаЧастичное обновление
ИдемпотентностьДаНе гарантирована

DELETE: Удаление ресурса

DELETE удаляет указанный ресурс.

Удаление ресурса

DELETE /users/123
HTTP/1.1 204 No Content
# Или с телом ответа (информация о удалении)
HTTP/1.1 200 OK
Content-Type: application/json

{
    "id": 123,
    "deleted": true,
    "message": "Пользователь удалён"
}

DELETE для коллекций

# Удаление всех пользователей со статусом inactive
DELETE /users?status=inactive   # Не стандартизировано, лучше POST /users/bulk-delete

Каскадное удаление

DELETE /users/123

Вопрос: удаляются ли заказы пользователя? API должен документировать такое поведение.

HEAD и OPTIONS: Вспомогательные методы

HEAD

HEAD работает как GET, но возвращает только заголовки, без тела. Полезен для проверки существования ресурса или получения метаданных.

HEAD /users/123
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 256
Last-Modified: Wed, 15 Jan 2024 10:30:00 GMT
ETag: "abc123"

Используется для:

  • Проверка существования ресурса (без загрузки данных)
  • Получение Content-Length (размера ответа)
  • Получение Last-Modified (проверка актуальности кеша)
  • Проверка доступности (health check)

OPTIONS

OPTIONS возвращает список HTTP методов, поддерживаемых для ресурса.

OPTIONS /users/123
HTTP/1.1 204 No Content
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS

Используется для CORS preflight запросов (браузер проверяет, разрешён ли запрос с другого домена).

Безопасность и идемпотентность

Безопасные методы (Safe)

Безопасные методы не изменяют состояние сервера. Их можно вызывать сколько угодно раз — побочных эффектов не будет.

МетодБезопасныйПочему
GETДаТолько чтение
HEADДаТолько заголовки
OPTIONSДаТолько информация о методах
POSTНетСоздаёт или изменяет
PUTНетИзменяет
PATCHНетИзменяет
DELETEНетИзменяет

Почему безопасность важна: Поисковые роботы, префетчеры, браузеры могут автоматически делать GET, HEAD, OPTIONS запросы. Если эти методы изменяют данные — возможны катастрофы.

Идемпотентные методы (Idempotent)

Идемпотентный метод можно вызвать несколько раз подряд, и результат будет таким же, как от одного вызова.

МетодИдемпотентныйПочему
GETДаПовторное чтение даёт тот же результат
HEADДаПовторное чтение даёт те же заголовки
OPTIONSДаПовторный запрос даёт те же методы
PUTДаПовторная полная замена ресурса даёт тот же результат
DELETEДаПовторное удаление уже удалённого ресурса ничего не меняет
POSTНетПовторная отправка может создать второй ресурс
PATCHНе гарантированаЗависит от реализации

Пример идемпотентности:

DELETE /users/123  # первый раз — удаляет
DELETE /users/123  # второй раз — ресурс уже удалён, но ответ тот же (404 или 204)
PUT /users/123 {"name": "Иван"}  # первый раз — создаёт или обновляет
PUT /users/123 {"name": "Иван"}  # второй раз — результат тот же
POST /users {"name": "Иван"}  # первый раз — создаёт пользователя
POST /users {"name": "Иван"}  # второй раз — может создать второго пользователя

Почему идемпотентность важна: При сетевых сбоях клиент может не знать, дошёл ли запрос. Если метод идемпотентен, клиент может безопасно повторить запрос.

PUT vs POST: Практические правила

СценарийКакой методПочему
Создание с автоматическим IDPOSTКлиент не знает ID
Создание с известным IDPUTКлиент знает ID, PUT идемпотентен
Полная замена ресурсаPUTPUT заменяет целиком
Частичное обновлениеPATCHPATCH изменяет только указанные поля
Загрузка файлаPOSTСоздание нового ресурса
Выполнение действияPOSTНе CRUD операция
Поиск со сложным запросомPOSTGET с длинным телом не поддерживается

Примеры использования методов

CRUD операции для пользователя

# Создать пользователя (сервер генерирует ID)
POST /users

# Получить пользователя
GET /users/123

# Полностью заменить пользователя
PUT /users/123

# Частично обновить пользователя
PATCH /users/123

# Удалить пользователя
DELETE /users/123

Работа с коллекцией

# Получить всех пользователей
GET /users

# Создать пользователя
POST /users

# Удалить всех пользователей (редко, обычно не делают)
DELETE /users  # осторожно!

Действия (не CRUD)

# Активация пользователя
POST /users/123/activate

# Отправка email
POST /emails/send

# Поиск со сложным запросом (тело в GET не поддерживается везде)
POST /search

Частые ошибки с HTTP методами

Ошибка 1: GET для изменения данных

GET /users/123/delete
GET /api/charge?amount=100

Почему плохо: Поисковые роботы, префетчеры могут вызвать эти URL. GET должен быть безопасным.

Как исправить: DELETE /users/123, POST /api/charge.

Ошибка 2: POST для получения данных

POST /getUser
{"id": 123}

Почему плохо: POST не кешируется. POST не идемпотентен.

Как исправить: GET /users/123.

Ошибка 3: PUT для частичного обновления

PUT /users/123
{"phone": "+7-999-123-45-67"}
# Остальные поля (name, email) удаляются или становятся NULL

Как исправить: Использовать PATCH для частичного обновления.

Ошибка 4: Неправильный статус-код для POST

POST /users
→ HTTP/1.1 200 OK

Как исправить: 201 Created с заголовком Location.

Ошибка 5: DELETE с телом запроса

DELETE /users
{"ids": [1, 2, 3]}

DELETE по спецификации может иметь тело, но не все серверы и прокси это поддерживают.

Как исправить: POST /users/bulk-delete с телом.

Резюме для системного аналитика

  1. HTTP методы — это глаголы REST. Они определяют действие над ресурсом. GET для чтения, POST для создания, PUT для полной замены, PATCH для частичного изменения, DELETE для удаления.

  2. GET — безопасный и идемпотентный. Только чтение, не изменяет данные. Может кешироваться. Должен использоваться для всех операций чтения.

  3. POST — не идемпотентный. Используется для создания ресурсов (когда ID генерирует сервер) и для любых действий, не вписывающихся в CRUD.

  4. PUT — идемпотентный. Полностью заменяет ресурс. Клиент знает ID ресурса. Отсутствующие поля удаляются.

  5. PATCH — частичное обновление. Изменяет только указанные поля. Не обязан быть идемпотентным, но может быть.

  6. DELETE — идемпотентный. Удаляет ресурс. Повторный DELETE того же ресурса не должен вызывать ошибку.

  7. Безопасность и идемпотентность — важные свойства. GET, HEAD, OPTIONS — безопасны. GET, HEAD, OPTIONS, PUT, DELETE — идемпотентны. POST — ни то, ни другое. PATCH — не гарантирует идемпотентность.

Проверка знаний

Вопрос 1 из 4
Какой HTTP-метод обычно используют для чтения ресурса?
Какой метод обычно используют для создания нового ресурса в коллекции?
Чем PUT обычно отличается от PATCH?
Почему GET не должен менять состояние системы?

Вопросы, где были ошибки