Питання 7 · Розділ 6

Чому GET та DELETE ідемпотентні?

Метод GET не змінює дані на сервері. Скільки разів ви не запросите один і той самий ресурс — результат буде однаковим.

Мовні версії: English Russian Ukrainian

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. Запит 1: Ресурс існує. Видаляємо. Код 200 або 204.
  2. Запит 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 дизайн]]