В чому різниця між PUT та PATCH?
Обидва методи використовуються для оновлення ресурсу, але працюють по-різному.
Junior Level
Обидва методи використовуються для оновлення ресурсу, але працюють по-різному.
PUT — Повне оновлення
- Замінює все представлення ресурса на те, що надіслав клієнт. Полів, яких немає в тілі запиту, мають бути видалені або скинуті до значень за замовчуванням.
- Потрібно надіслати всі поля, навіть ті, що не змінилися
- Якщо не надіслати якеся поле — воно буде видалене або встановлене в null
PUT /users/1
{
"name": "Ivan",
"age": 30,
"email": "ivan@example.com"
}
PATCH — Часткове оновлення
- Оновлює лише ті поля, які були надіслані
- Економить трафік: для об’єкта в 200 полів зміна одного поля через PATCH економить ~95% тіла запиту.
PATCH /users/1
{
"age": 31
}
// Решта полів залишаються без змін
Порівняння:
| Критерій | PUT | PATCH |
|---|---|---|
| Обсяг даних | Повний об’єкт | Тільки змінені поля |
| Ідемпотентність | Завжди ідемпотентний | Залежить від реалізації |
| Аналогія в SQL | UPDATE всіх колонок | UPDATE конкретних колонок |
Коли PUT кращий за PATCH
Використовуйте PUT для повних замін невеликих об’єктів — простіший у реалізації та однозначний. Використовуйте PATCH для великих об’єктів або коли кілька клієнтів можуть паралельно змінювати різні поля.
Middle Level
Семантика методів
PUT (Replace)
- Ідемпотентність: Завжди ідемпотентний. Скільки б разів не надіслати один і той самий запит — результат однаковий
- DB Analogy:
UPDATE users SET name=?, age=?, email=? ...(оновлення всіх колонок)
PATCH (Partial Update)
- Ідемпотентність: Не гарантується. Залежить від реалізації
- DB Analogy:
UPDATE users SET age = age + 1(не ідемпотентно) абоSET age = 30(ідемпотентно)
Специфікації PATCH
- JSON Merge Patch (RFC 7386):
- Клієнт надсилає JSON:
{"age": 31} - Сервер просто мержить його з поточним об’єктом
- Мінус: Складно видалити поле (потрібно домовитися, що
null— це видалення)
Ключова відмінність: Merge Patch каже «що змінити» (декларативно), а JSON Patch каже «як змінити» (послідовність операцій: add, remove, replace).
- Клієнт надсилає JSON:
- JSON Patch (RFC 6902):
- Клієнт надсилає масив інструкцій:
[ { "op": "replace", "path": "/age", "value": 31 }, { "op": "remove", "path": "/middleName" } ] - Плюс: Атомарність і гнучкість. Можна додавати елементи в масиви, видаляти конкретні поля
- Клієнт надсилає масив інструкцій:
Оптимістичне блокування (ETag)
- Клієнт отримує ресурс із заголовком
ETag: "v1" - Клієнт надсилає
PUT/PATCHіз заголовкомIf-Match: "v1" - Якщо
ETagстав “v2” — сервер поверне 412 Precondition Failed
Діагностика
- 422 Unprocessable Entity: Якщо PATCH логічно невиконувана (наприклад, видалення обов’язкового поля)
- Hibernate/JPA: При PATCH використовуйте
nullValuePropertyMappingStrategy = IGNOREв MapStruct, щоб випадково не затерти поля
Senior Level
Проблема “Lost Updates” та Optimistic Locking
Що якщо два користувачі одночасно прочитали ресурс (age=20) і вирішили його оновити?
- PUT-проблема: Перший оновив до 21, другий — до 25. Зміни першого втрачено.
- PATCH-рішення: Якщо PATCH робить
age = age + 1, підсумок буде 22 (обидві зміни враховано).
Продуктивність і Highload
- Bandwidth: PATCH економить трафік на великих об’єктах (профіль із сотнями полів)
- Validation: PUT простіше валідувати (повна схема). PATCH вимагає складної логіки валідації “тільки надісланих полів”
- Reflection у Java: Реалізація PATCH часто вимагає Jackson
JsonNodeдля визначення, чи було полеnullабо відсутнім
Реалізація PATCH у Spring
Будьте обережні з merge() у Hibernate. Якщо створити новий об’єкт і викликати merge(), можна випадково затерти поля, що не прийшли в PATCH, перетворивши його на кривий PUT.
Edge Cases
- Якщо PATCH містить
{"op": "add", "path": "/tags", "value": "new"}— це не ідемпотентно (при повторі додасться ще один тег) - Для ідемпотентності PATCH використовуйте детерміновані операції (replace, remove)
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- PUT замінює ресурс цілком — поля, яких немає в запиті, видаляються або обнуляються
- PATCH оновлює лише надіслані поля — економить трафік на великих об’єктах
- PUT завжди ідемпотентний; PATCH ідемпотентний тільки при детермінованих операціях
- JSON Merge Patch (RFC 7386) — декларативний підхід: «що змінити»
- JSON Patch (RFC 6902) — імперативний підхід: масив операцій (add, remove, replace)
- Optimistic Locking через ETag + If-Match запобігає конфлікту паралельних оновлень
- PUT простіше валідувати (повна схема), PATCH вимагає складної валідації часткових даних
Часті уточнюючі запитання:
- Що таке Lost Update Problem? — Два клієнти читають ресурс і оновлюють паралельно; зміни першого втрачаються
- Як реалізувати PATCH у Hibernate? — Використовувати nullValuePropertyMappingStrategy = IGNORE в MapStruct
- Що поверне сервер при 412 Precondition Failed? — ETag змінився з моменту читання, ресурс застарів
- Коли PUT кращий за PATCH? — Для невеликих об’єктів і коли потрібна однозначна повна заміна
Червоні прапорці (НЕ говорити):
- «PATCH завжди ідемпотентний» — add у колекцію не ідемпотентне
- «PUT оновлює лише передані поля» — PUT замінює весь об’єкт цілком
- «Різниці між PUT і PATCH немає» — PUT = повна заміна, PATCH = часткове оновлення
- «Merge Patch і JSON Patch — одне й те саме» — Merge Patch декларативна, JSON Patch — послідовність операцій
Пов’язані теми:
- [[Що таке ідемпотентність (idempotency)]]
- [[Які HTTP методи ідемпотентні]]
- [[Які основні HTTP методи використовуються в REST]]
- [[Як правильно іменувати REST endpoints]]