← Назад к вопросам

В чем разница между PUT и PATCH?

1.3 Junior🔥 181 комментариев
#Интеграции и API

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между PUT и PATCH: полное обновление vs частичное

При проектировании API часто встаёт вопрос: как обновить существующий ресурс? И здесь есть два методов — PUT и PATCH — которые решают одну задачу по-разному. Это важное различие для правильного дизайна API.

PUT: полная замена ресурса

PUT — это HTTP метод для полной замены существующего ресурса новыми данными. Семантика: "возьми этот ресурс и замени его полностью на то, что я отправляю".

Пример: обновление профиля пользователя

Исходное состояние:

GET /api/v1/users/user_123
Response: {
  "id": "user_123",
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "+1234567890",
  "country": "USA",
  "age": 30
}

PUT запрос (полная замена):

PUT /api/v1/users/user_123
Content-Type: application/json
Body: {
  "name": "Jane Smith",
  "email": "jane@example.com",
  "phone": "+0987654321",
  "country": "UK",
  "age": 28
}

Response: 200 OK
{
  "id": "user_123",
  "name": "Jane Smith",
  "email": "jane@example.com",
  "phone": "+0987654321",
  "country": "UK",
  "age": 28
}

Важное правило PUT: Если в Body не отправить какое-то поле, оно удалится или вернёться к значению по умолчанию. Это полная замена!

Перед: {"name": "John", "email": "john@ex.com", "phone": "+123"}
PUT с: {"name": "Jane", "email": "jane@ex.com"}
После: {"name": "Jane", "email": "jane@ex.com", "phone": null}

PATCH: частичное обновление

PATCH — это HTTP метод для частичного обновления ресурса. Семантика: "обнови только те поля, которые я отправляю, остальное оставь как было".

Пример: обновление профиля пользователя

Исходное состояние (то же):

{
  "id": "user_123",
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "+1234567890",
  "country": "USA",
  "age": 30
}

PATCH запрос (только изменение):

PATCH /api/v1/users/user_123
Content-Type: application/json
Body: {
  "phone": "+0987654321",
  "country": "UK"
}

Response: 200 OK
{
  "id": "user_123",
  "name": "John Doe",      ← НЕ изменилось
  "email": "john@example.com",  ← НЕ изменилось
  "phone": "+0987654321",        ← ИЗМЕНИЛОСЬ
  "country": "UK",              ← ИЗМЕНИЛОСЬ
  "age": 30                      ← НЕ изменилось
}

По сравнению с PUT, мы отправляем только то, что хотим изменить!

Таблица сравнения

АспектPUTPATCH
СемантикаПолная заменаЧастичное обновление
Обязательные поляВсе поля требуютсяТолько изменяемые поля
Отсутствующие поляУдаляются/сбрасываютсяОстаются как были
IdempotentДа (100%)Да (обычно)
BodyПолный ресурсТолько дельта
Когда использоватьРедактирование формы целикомБыстрое обновление одного поля
ПроизводительностьОтправляем больше данныхОтправляем минимум данных
Сложность реализацииПрощеСложнее (нужна merge логика)

Когда использовать PUT

1. Обновление целой формы

Когда пользователь редактирует весь профиль целиком:

<form>
  <input value="John Doe" name="name">
  <input value="john@ex.com" name="email">
  <input value="+123456" name="phone">
  <input value="USA" name="country">
  <button>Save All</button>  ← PUT
</form>

2. Замена конфигурации

Когда обновляешь всю конфигурацию приложения сразу:

Прежде:
{"theme": "dark", "lang": "en", "notifications": "all"}

PUT /api/v1/settings
{"theme": "light", "lang": "ru", "notifications": "none"}

После:
{"theme": "light", "lang": "ru", "notifications": "none"}

3. Синхронизация состояния

Когда мобильное приложение отправляет весь актуальный state:

PUT /api/v1/sync/user_state
Body: [полное состояние приложения]

Когда использовать PATCH

1. Быстрые изменения одного поля

Пользователь изменил только email:

PATCH /api/v1/users/user_123
{"email": "newemail@example.com"}

Не нужно отправлять все остальные поля!

2. Обновления из разных источников

Администратор и пользователь одновременно могут обновлять разные поля:

Админ:
PATCH /api/v1/users/user_123
{"status": "suspended"}

Пользователь:
PATCH /api/v1/users/user_123
{"phone": "+9999999"}

Результат: оба изменения сохранены

3. Условные обновления

Обновить только если выполнено условие:

PATCH /api/v1/orders/order_123
If-Match: "etag_v2"
Body: {"status": "shipped"}

Если etag совпадает → обновляем
Если нет (был изменён другим процессом) → 412 Precondition Failed

4. API для частичных обновлений

Внутренние сервисы часто используют PATCH для микро-обновлений:

PATCH /api/v1/users/user_123
Body: [{"op": "replace", "path": "/phone", "value": "+123"}]

Это RFC 6902 (JSON Patch) стандарт.

Реальные примеры из моей работы

Сценарий 1: Обновление профиля пользователя

Пользователь нажимает "Edit Profile". Какой метод использовать?

Ответ: зависит от интерфейса

  • Если форма показывает все поля → PUT (пользователь редактирует весь профиль)
  • Если форма показывает только изменённые поля → PATCH (быстрое обновление)

Сценарий 2: API для мобильного приложения

Мобильное приложение может отправлять только изменённые поля:

ПОШУЛся:
GET /api/v1/users/me
Response: {"name": "John", "email": "john@ex.com", "age": 30}

Пользователь изменил возраст на 31

PATCH /api/v1/users/me
Body: {"age": 31}  ← только это

Делает запрос меньше, батарея дольше держит.

Сценарий 3: Конфликты в системе

Когда несколько процессов обновляют разные поля:

Процесс A:                  Процесс B:
PATCH /users/123            PATCH /users/123
{"name": "Alice"}           {"email": "alice@ex.com"}

Результат:
{"name": "Alice", "email": "alice@ex.com"}

Оба изменения сохранены! (благодаря PATCH)

С PUT было бы конфликт:

Процесс A:
Прочитал: {"name": "John", "email": "john@ex.com"}
Изменил: {"name": "Alice", "email": "john@ex.com"}
Отправил PUT

Процесс B (в то же время):
Прочитал: {"name": "John", "email": "john@ex.com"}
Изменил: {"name": "John", "email": "alice@ex.com"}
Отправил PUT

Результат: потеря данных (overwrite)

Best Practice для API Design

1. Используй PUT для:

  • Полное обновление ресурса
  • Когда client отправляет полное состояние
  • Когда отсутствующее поле = удалить значение

2. Используй PATCH для:

  • Частичное обновление
  • Когда client отправляет только дельту
  • Когда отсутствующее поле = оставить как было

3. Реакция на отсутствие поля:

# PUT реализация
def update_user_put(user_id, data):
    user = User.get(user_id)
    user.name = data.get('name')  # Если нет → None
    user.email = data.get('email')
    user.phone = data.get('phone', None)  # Явно None
    user.save()

# PATCH реализация
def update_user_patch(user_id, data):
    user = User.get(user_id)
    for key, value in data.items():
        setattr(user, key, value)  # Обновляем только отправленные
    user.save()

Идемпотентность обоих методов

Оба PUT и PATCH должны быть идемпотентными — повторный вызов с теми же данными даёт тот же результат:

Первый раз: PATCH /users/123 {"age": 31} → age = 31
Второй раз: PATCH /users/123 {"age": 31} → age = 31 (не меняется)

Это критично для надежности (если запрос отправился дважды — no problem).

Мой выбор в реальных проектах

В большинстве современных API я предпочитаю PATCH:

✓ Меньше данных в сети ✓ Меньше risk конфликтов ✓ Проще для микросервисной архитектуры ✓ Лучше для мобильных приложений

Но PUT остаётся полезным для: ✓ Редиса кэши (Redis часто использует full replace) ✓ Configurations (всегда замена конфига полностью) ✓ Legacy систем

Выбор между PUT и PATCH — это часть стратегического дизайна API, и я всегда обсуждаю это с архитектором при планировании.