Чому GET та DELETE ідемпотентні?
Метод GET не змінює дані на сервері. Скільки разів ви не запросите один і той самий ресурс — результат буде однаковим.
Junior Level
GET — ідемпотентний, тому що тільки читає
Метод GET не змінює дані на сервері. Скільки разів ви не запросите один і той самий ресурс — результат буде однаковим.
GET /users/1 → Поверне дані користувача
GET /users/1 → Знову поверне ті самі дані
GET /users/1 → І знову ті самі дані
GET називається “безпечним” (Safe) — він не змінює ресурс, до якого звертається клієнт. GET може писати в лог або оновлювати лічильник переглядів у Redis. Це допустимо! “Безпечний” у HTTP означає “не впливає на відповідь, яку отримає клієнт”.
DELETE — ідемпотентний, тому що результат однаковий
Перший DELETE видаляє ресурс. Усі наступні DELETE підтверджують, що ресурсу вже немає. Підсумковий стан сервера (“ресурсу немає”) не змінюється.
DELETE /users/1 → 200 OK (ресурс видалено)
DELETE /users/1 → 404 Not Found (ресурсу вже немає)
DELETE /users/1 → 404 Not Found (ресурсу все ще немає)
// Різні коди відповіді (200 vs 404) не порушують ідемпотентність, тому що
// ідемпотентність — про стан ресурсу на сервері, а не про те, що бачить клієнт.
// Ресурс видалено після першого виклику — наступні нічого не змінюють.
Після всіх викликів стан сервера однаковий — користувача немає.
Middle Level
GET: Ідемпотентність через Безпеку
Згідно з RFC 9110, безпечні методи не мають побічних ефектів, яких клієнт би очікував.
Приховані зміни: GET може писати в лог або оновлювати лічильник переглядів у Redis. Це допустимо! Ідемпотентність і безпека стосуються відповідальності за ресурс. Технічні побічні ефекти (логи, аналітика, прогрів кешу) не порушують контракт GET.
Ризик: Якщо реалізувати GET /user/1/delete, браузер може “попередньо завантажити” посилання і випадково видалити користувача. Саме тому GET зобов’язаний бути безпечним.
DELETE: Ідемпотентність через Інвариантність
DELETE змінює стан, тому не безпечний, але ідемпотентний.
Механіка:
- Запит 1: Ресурс існує. Видаляємо. Код
200або204. - Запит 2: Ресурсу немає. Намагаємось видалити. Код
404.
Ключовий момент: Підсумковий стан сервера (“Ресурсу немає”) не змінився після другого виклику.
М’яке видалення (Soft Delete)
Якщо DELETE ставить прапорець is_deleted = true і оновлює deleted_at — він все одно залишається ідемпотентним. Повторний виклик просто ще раз встановить true.
Продуктивність
- Результати DELETE не кешуються, але DELETE інвалідує кеш для цього URI
- Для пакетного видалення використовуйте
DELETE /resources?ids=1,2,3замістьPOST /delete-multiple(друге не ідемпотентне)
Діагностика
- Величезна кількість 404 на DELETE запитах вказує на агресивні Retry-політики клієнта
- При тестуванні завжди робіть два однакових виклики DELETE поспіль
Senior Level
Видалення у розподілених системах
У мікросервісах DELETE може ініціювати ланцюжок подій (наприклад, через Kafka).
Edge Case: Перший DELETE видалив запис і надіслав подію UserDeleted. Другий DELETE (Retry через лаг мережі) прийшов пізніше — сервер не повинен надсилати подію UserDeleted вдруге, інакше downstream-сервіси можуть збоювати.
Рішення: Перевірка існування ресурсу перед видаленням і надсиланням події.
Caching DELETE
DELETE інвалідує (скидає) кеш для цього URI на всіх проміжних вузлах. Це гарантує, що наступний GET не поверне старі дані з кешу.
Batch Delete: POST /delete-multiple — не ідемпотентне. Для ідемпотентності використовуйте DELETE /resources?ids=1,2,3.
Ідемпотентність і розподілені події
При використанні черг (Kafka, RabbitMQ) DELETE має гарантувати, що подія видалення надсилається тільки один раз, навіть при повторних викликах.
GET: результат однаковий, тому що нічого не змінюється.
DELETE: результат однаковий, тому що після першого виклику змінювати вже нічого.
Моніторинг
- Відстежуйте кількість 404 відповідей на DELETE запити
- Високий відсоток 404 на DELETE = агресивні Retry-політики на клієнті
- При інтеграції з event-driven архітектурою перевіряйте, що повторний DELETE не генерує дублікати подій
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- GET ідемпотентний, тому що тільки читає — Safe метод за RFC 9110
- GET може писати в логи і кеш — це допустимо, «безпека» стосується відповіді клієнту
- DELETE ідемпотентний: після першого виклику ресурсу немає, повторні нічого не змінюють
- Різні коди відповіді (200 → 404) не порушують ідемпотентність — важливий стан сервера
- DELETE інвалідує кеш для даного URI, щоб наступний GET не повернув старі дані
- Soft Delete (is_deleted = true) залишається ідемпотентним — повторний виклик просто ставить true ще раз
- DELETE у розподілених системах не повинен надсилати подію видалення повторно
Часті уточнюючі запитання:
- Чому GET /user/1/delete — це погано? — Браузери можуть попередньо завантажувати GET-посилання, що випадково видалить користувача
- Як забезпечити ідемпотентність пакетного видалення? — DELETE /resources?ids=1,2,3, а не POST /delete-multiple
- Що якщо DELETE викликано двічі в event-driven системі? — Другий виклик не повинен генерувати дублікат події
- GET оновлює лічильник переглядів — це порушує ідемпотентність? — Ні, технічні побічні ефекти допустимі
Червоні прапорці (НЕ говорити):
- «DELETE не ідемпотентний, тому що другий раз повертає 404» — стан сервера однаковий
- «GET має бути абсолютно без побічних ефектів» — логи, аналітика, прогрів кешу допустимі
- «Для пакетного видалення краще POST» — DELETE з query-параметрами ідемпотентний, POST — ні
- «Різні коди відповіді = різна ідемпотентність» — ідемпотентність про стан, не про код відповіді
Пов’язані теми:
- [[Що таке ідемпотентність (idempotency)]]
- [[Які HTTP методи ідемпотентні]]
- [[Чи є POST ідемпотентним]]
- [[Які основні HTTP методи використовуються в REST]]
- [[Що таке RESTful API дизайн]]