Отличия POST, PUT и PATCH

Короткая модель

МетодКто выбирает URIСмыслИдемпотентность
POSTобычно серверобработать representation или создать subordinate resourceнет по умолчанию
PUTобычно клиент знает URIполностью заменить representation ресурсада
PATCHURI уже известенприменить частичное изменениезависит от patch document

POST

POST /orders HTTP/1.1
Content-Type: application/json
Idempotency-Key: request-123
 
{"productId":7,"quantity":2}

Успех создания: 201 Created и Location: /orders/42. Если клиент повторяет POST после timeout, idempotency key позволяет серверу вернуть результат первой операции вместо дубликата. Это прикладной контракт, не автоматическое свойство HTTP.

PUT

PUT /profiles/42 HTTP/1.1
Content-Type: application/json
 
{"name":"Ada","timezone":"UTC"}

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

PATCH

Merge Patch:

PATCH /profiles/42 HTTP/1.1
Content-Type: application/merge-patch+json
 
{"timezone":"Europe/Moscow"}

Операция “установить timezone” может быть идемпотентной. Операция “увеличить balance на 10” — нет. Поэтому PATCH как метод не гарантирует идемпотентность. JSON Patch и Merge Patch имеют разную семантику; просто application/json оставляет формат неясным.

Конкурентность

Для PUT/PATCH полезен optimistic lock:

If-Match: "version-7"

При несовпадении версии сервер возвращает 412 Precondition Failed или договорной 409 Conflict, не затирая изменение другого клиента.

Типичные сбои

  • Использовать PUT как частичный update, но не описать судьбу отсутствующих полей.
  • Автоматически retry POST без idempotency key.
  • Считать любой PATCH идемпотентным.
  • Возвращать 201 при обычном обновлении существующего ресурса без создания.
  • Не различать отсутствующее поле и явный null.

Вопросы для собеседования

Почему PUT идемпотентен? Повтор полной установки representation ведёт к тому же целевому состоянию.

Можно ли сделать POST идемпотентным? Да, прикладным ключом идемпотентности и хранением результата.

PATCH всегда частичный PUT? Нет, он применяет patch document с собственной семантикой.

Как не потерять параллельное обновление? ETag/version и условный request.

См. REST, Версии протокола HTTP.