Короткий ответ
PUT заменяет ресурс целиком и идемпотентен; PATCH применяет частичное изменение и не обязан быть идемпотентным. Если ресурс не найден, обычно возвращают 404, но PUT иногда допускает создание ресурса по заданному URL (тогда 201).
Как это работает подробнее
PUT ожидает полное представление ресурса — поля, которые не переданы, по спецификации REST должны считаться отсутствующими/сброшенными. PATCH передаёт только изменяемые поля или набор операций (например, JSON Merge Patch или JSON Patch по RFC 6902).
Пример кода
example.py
# FastAPI, намеренно показана разница PUT/PATCH
@app.put("/items/{item_id}")
def replace_item(item_id: int, item: Item):
if item_id not in db:
return JSONResponse(status_code=404, content={"detail": "not found"})
db[item_id] = item.dict() # заменяет ресурс целиком
return db[item_id]
@app.patch("/items/{item_id}")
def update_item(item_id: int, patch: dict):
if item_id not in db:
return JSONResponse(status_code=404, content={"detail": "not found"})
db[item_id].update(patch) # частичное обновление
return db[item_id]Что использовать на практике
- Рекомендация. для простых API часто используют PATCH с частичным JSON-объектом, который мержится с текущими данными в коде обработчика. PUT уместен, когда клиент владеет полным представлением ресурса (например, конфигурация). Решение зависит от соглашений конкретного API — это нужно явно документировать в контракте.
Подводные камни
- Риски. реализовывать PATCH так, что непереданные поля интерпретируются как "сбросить в null" (это поведение PUT, а не PATCH); считать PUT автоматически идемпотентным, если сервер генерирует значения на основе текущего времени при каждом обновлении; не возвращать корректный статус при отсутствии ресурса.