Что позволяет свойство идемпотентности у HTTP методов
Что проверяют
Понимаете ли вы, что идемпотентность это про состояние сервера, а не про одинаковый ответ, и умеете ли превратить свойство в проверки. Для тестировщика это основа сценариев с повторами и сетевыми сбоями.
Как отвечать
Определение: повторное применение того же запроса оставляет состояние сервера таким же, каким оно стало после первого применения. По спецификации HTTP идемпотентны GET, HEAD, PUT, DELETE, OPTIONS, TRACE. Не идемпотентны POST и, в общем случае, PATCH: он идемпотентен только если тело описывает результат, а не операцию вроде «прибавь единицу».
Отдельно назовите безопасность: GET, HEAD, OPTIONS, TRACE вообще не меняют состояние, это более сильное свойство, и безопасный метод всегда идемпотентен.
Что свойство даёт на практике:
- клиент, прокси и мобильное приложение могут повторить запрос после таймаута, не боясь второго списания;
- ретраи можно встроить в клиент, балансировщик и автотесты;
- для неидемпотентных операций дубли закрывают ключом идемпотентности, который передают заголовком, а сервер хранит и отдаёт первый результат.
Переведите в проверки: отправить запрос дважды и сравнивать не ответы, а состояние (одна запись вместо двух, счётчики на месте); отправить два одинаковых запроса параллельно и поймать гонку; оборвать соединение после отправки и повторить.
Где спотыкаются
Путают идемпотентность с одинаковым ответом. Второй DELETE честно вернёт другой код, чем первый, а PUT может вернуть обновление вместо создания. Отличаться может и код, и тело, состояние не должно.
Второе: считают, что раз GET безопасный, дёргать его можно как угодно. В реальных сервисах GET растит счётчик просмотров, пишет событие в аналитику, продлевает сессию. Если ручка меняет данные, это дефект проектирования, и его стоит завести.
Третье: проверяют только тело ответа и забывают про побочные эффекты. Повтор запроса может не задвоить строку в базе, но отправить второе письмо, второй пуш и второй вызов вебхука партнёру. Смотреть надо на всю цепочку, а не на код ответа.