Что такое идемпотентность HTTP-запроса?

Ответ

Идемпотентность — свойство HTTP-метода, означающее, что многократное выполнение одного и того же запроса с одинаковыми данными приводит к одному и тому же результату и не вызывает дополнительных побочных эффектов после первого успешного выполнения.

Идемпотентные методы (согласно RFC 7231):

  • GET: Получение ресурса. Повторные запросы не изменяют состояние сервера.
  • PUT: Создание или полное замещение ресурса по известному URI. Повторные запросы с тем же телом не создают новые ресурсы.
  • DELETE: Удаление ресурса. После первого успешного удаления ресурса последующие запросы должны возвращать 404 Not Found или 410 Gone, что является одинаковым результатом.
  • HEAD: Аналогичен GET, но без тела ответа.
  • OPTIONS и TRACE: Также идемпотентны.

Неидемпотентный метод:

  • POST: Каждый запрос обычно создаёт новый ресурс, меняя состояние сервера.

Пример идемпотентности PUT:

PUT /api/users/123 HTTP/1.1
Content-Type: application/json

{"name": "Alice", "role": "admin"}

Почему это важно для тестирования и разработки API?

  1. Безопасность повторных запросов: Клиент может безопасно повторять запрос при таймаутах или сетевых сбоях, не опасаясь дублирования операций (например, списания денег дважды).
  2. Тестирование: Идемпотентные эндпоинты проще тестировать, так как их можно вызывать многократно, не очищая состояние.
  3. Проектирование: При создании API следует стремиться к идемпотентности для методов обновления (PUT, PATCH для определённых операций) и удаления.

Ответ 18+ 🔞

Слушай, а вот это слово — идемпотентность — звучит, будто диагноз какой-то, а на деле всё просто, как три копейки. Представь, ты нажимаешь кнопку лифта на своём этаже. Раз нажал — лампочка загорелась, лифт едет. Ты её десять раз долбишь — хуй с ним, результат-то один: лифт всё равно приедет только один раз. Не приедет за тобой десять кабинок подряд, верно? Вот это и есть идемпотентность, ёпта. Сделал запрос — сервер что-то сделал. Повторил его сто раз — сервер больше не дергается, результат не меняется, побочных эффектов новых не возникает. Красота!

Вот, смотри, какие методы в HTTP такие спокойные, предсказуемые, как этот лифт:

  • GET: Ты просто смотришь, что в холодильнике. Посмотрел раз, посмотрел десять — количество котлет не изменится, если ты, конечно, между запросами руку не засунешь.
  • PUT: Это как полностью переписать файл на компе. Был файл recipe.txt с текстом "Соль". Ты заменил его на файл с текстом "Соль, перец". Сколько раз ни выполняй эту команду — в конце концов в файле будет чётко "Соль, перец". Новых файлов не создаётся, старый просто перезаписывается. Идемпотентно, сука!
  • DELETE: Удалил письмо из спама. Полез проверять — а его нет. Удалил ещё раз — да нет его, блядь, ну что ты пристал? Результат тот же — письма нет. Всё логично.
  • HEAD, OPTIONS, TRACE — они тоже из этой оперной труппы, по сути безобидные.

А вот POST — это уже не идемпотентный ушлёпок. Это как нажать кнопку «Заказать пиццу». Нажал раз — одна пицца едет. Нажал десять раз в панике из-за лагов сайта — будь готов встречать десять курьеров и объяснять жене, нахуя столько теста. Каждый запрос создаёт что-то новое, меняет состояние вселенной. Непредсказуемо, волнующе, пиздец как неудобно для автоматических повторов.

Вот, глянь, как PUT выглядит в деле — всё чинно, благородно:

PUT /api/users/123 HTTP/1.1
Content-Type: application/json

{"name": "Alice", "role": "admin"}

Сколько ни шли этот запрос — юзер с айди 123 в итоге будет Алисой-админом. Не создастся сто Алис, роль не поменяется на "adminadminadmin". Всё стабильно.

А нахуя это всё надо, спросишь? Да затем, чувак!

  1. Чтобы не обосраться при повторах. Сеть — она штука ненадёжная. Отправил запрос на списание 100 рублей, ответ не пришёл. Если метод идемпотентный (условно, как PUT на обновление баланса), можно смело послать запрос ещё раз. И ещё. Сервер, получив второй такой же запрос, поймёт: «А, так баланс уже обновлён, окей», и не спишет деньги повторно. Если бы это был POST на списание — пиши пропало, будут тебе двойные, тройные списания, и потом будешь с банком ебаться, как Толстой с Муму.
  2. Тестировать проще. Написал скрипт, который тестирует твой АПИ-метод. Запустил его сто раз подряд. Если метод идемпотентный — ничего не сломается, состояние системы не превратится в хаос, и ты не получишь в базе данных овердохуища дубликатов. Можно спокойно дебажить.
  3. Головой думать при проектировании. Когда делаешь АПИ, сразу думай: «А можно ли этот метод сделать идемпотентным?». Обновление данных (PUT) — почти всегда да. Какое-то сложное действие, которое нельзя повторять (типа той же транзакции) — тут уже POST и дополнительные механизмы защиты от повторов. Идея в том, чтобы максимизировать предсказуемость, а не создавать себе же и клиентам поле для потенциального ебла.

Короче, идемпотентность — это не заумь, а простая идея «сделал — и хватит». Делает жизнь на порядок проще, а нервы — целее. Вот и весь сказ, блядь.