Короткий ответ
Идемпотентный метод — такой, что повторное выполнение одного и того же запроса приводит к тому же результату на сервере, что и один вызов. GET, PUT, DELETE, HEAD, OPTIONS идемпотентны по спецификации; POST и PATCH — нет.
Как это работает подробнее
идемпотентность касается состояния ресурса на сервере, а не кода ответа — повторный DELETE уже удалённого ресурса может вернуть 404 вместо 204, но состояние ("ресурса нет") не меняется, поэтому метод остаётся идемпотентным.
Пример кода
example.py
# Нарушение идемпотентности PUT: намеренная ошибка — счётчик обновлений растёт при каждом вызове
@app.put("/items/{item_id}")
def replace_item(item_id: int, item: Item):
db[item_id] = item.dict()
db[item_id]["update_count"] = db[item_id].get("update_count", 0) + 1 # нарушает идемпотентность
return db[item_id]Что использовать на практике
- Рекомендация. идемпотентность важна при повторных попытках (retries) на нестабильной сети — HTTP-клиенты и прокси могут безопасно повторить идемпотентный запрос при таймауте, не опасаясь побочных эффектов. Для неидемпотентных операций (POST) повторную отправку нужно защищать явно, например ключом идемпотентности.
Подводные камни
- Риски. считать PUT идемпотентным автоматически, даже если обработчик добавляет побочные эффекты (например, инкрементирует счётчик версии при каждом вызове — это нарушает идемпотентность); путать идемпотентность с безопасностью (safe) — GET безопасен (не меняет состояние вовсе), а PUT идемпотентен, но может менять состояние при первом вызове.