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

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

1.6 Junior🔥 191 комментариев
#Работа с сетью

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

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

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

Разница между PUT и PATCH запросами

PUT и PATCH — это два HTTP метода для изменения ресурсов на сервере. Хотя оба используются для обновления данных, они работают по-разному и имеют разную семантику.

Основные различия

PUT — полное замещение (Total Replacement)

  • Заменяет весь ресурс целиком
  • Требует отправить все поля ресурса
  • Если не отправить какое-то поле, оно удалится или станет пустым
  • Идемпотентен — несколько одинаковых запросов дают одинаковый результат
  • Статус: 200 OK или 204 No Content
// PUT — отправляем весь объект целиком
final response = await http.put(
  Uri.parse('https://api.example.com/users/123'),
  headers: {'Content-Type': 'application/json'},
  body: jsonEncode({
    'id': 123,
    'name': 'John Doe',
    'email': 'john@example.com',
    'phone': '+1234567890',
    'address': '123 Main St',
  }),
);

PATCH — частичное обновление (Partial Update)

  • Обновляет только указанные поля
  • Можно отправить только нужные поля
  • Остальные поля остаются без изменений
  • Не всегда идемпотентен
  • Статус: 200 OK или 204 No Content
// PATCH — отправляем только то, что меняется
final response = await http.patch(
  Uri.parse('https://api.example.com/users/123'),
  headers: {'Content-Type': 'application/json'},
  body: jsonEncode({
    'name': 'Jane Doe', // Меняем только имя
  }),
);

Практический пример

Исходный ресурс на сервере:

{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "+1234567890",
  "address": "123 Main St"
}

Запрос PUT — нужно отправить всё

// Отправляем полный объект
final response = await http.put(
  Uri.parse('https://api.example.com/users/123'),
  headers: {'Content-Type': 'application/json'},
  body: jsonEncode({
    'id': 123,
    'name': 'Jane Doe',
    'email': 'jane@example.com',
    'phone': '+1234567890',
    'address': '123 Main St',
  }),
);

// Результат на сервере:
{
  "id": 123,
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": "+1234567890",
  "address": "123 Main St"
}

Если отправить неполный объект в PUT (ошибка!)

// ❌ Неправильно — отправляем не всё
final response = await http.put(
  Uri.parse('https://api.example.com/users/123'),
  body: jsonEncode({
    'name': 'Jane Doe', // Только имя!
    'email': 'jane@example.com',
  }),
);

// Результат — потеря данных!
{
  "id": 123,
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": null,        // Потеря данных!
  "address": null       // Потеря данных!
}

Запрос PATCH — отправляем только изменения

// ✅ Правильно — отправляем только то, что меняется
final response = await http.patch(
  Uri.parse('https://api.example.com/users/123'),
  headers: {'Content-Type': 'application/json'},
  body: jsonEncode({
    'name': 'Jane Doe',
    'email': 'jane@example.com',
  }),
);

// Результат на сервере — остальное не тронуто
{
  "id": 123,
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": "+1234567890",    // Осталось старое значение
  "address": "123 Main St"     // Осталось старое значение
}

Пример в Flutter приложении

Обновление профиля пользователя

class UserService {
  final http.Client _client = http.Client();
  final String _baseUrl = 'https://api.example.com';
  
  // PUT — полное обновление (редко нужен)
  Future<void> replaceUserProfile(User user) async {
    final response = await _client.put(
      Uri.parse('$_baseUrl/users/${user.id}'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(user.toJson()), // Весь объект!
    );
    
    if (response.statusCode != 200) {
      throw Exception('Failed to replace user');
    }
  }
  
  // PATCH — частичное обновление (часто нужен)
  Future<void> updateUserName(int userId, String newName) async {
    final response = await _client.patch(
      Uri.parse('$_baseUrl/users/$userId'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'name': newName}), // Только имя!
    );
    
    if (response.statusCode != 200) {
      throw Exception('Failed to update user');
    }
  }
  
  // PATCH — несколько полей
  Future<void> updateUserProfile(
    int userId, {
    String? name,
    String? email,
    String? phone,
  }) async {
    final data = <String, dynamic>{};
    
    if (name != null) data['name'] = name;
    if (email != null) data['email'] = email;
    if (phone != null) data['phone'] = phone;
    
    final response = await _client.patch(
      Uri.parse('$_baseUrl/users/$userId'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(data),
    );
    
    if (response.statusCode != 200) {
      throw Exception('Failed to update user profile');
    }
  }
}

Идемпотентность

PUT — идемпотентен

Несколько одинаковых PUT запросов приводят к одному результату:

// Первый запрос
http.put(..., body: jsonEncode({'name': 'John'}));
// Результат: name = 'John'

// Второй идентичный запрос
http.put(..., body: jsonEncode({'name': 'John'}));
// Результат: всё ещё name = 'John' (ничего не изменилось)

// Третий идентичный запрос
http.put(..., body: jsonEncode({'name': 'John'}));
// Результат: всё ещё name = 'John'

PATCH — может быть не идемпотентен

Это зависит от операции:

// Увеличение счетчика (не идемпотентно!)
// Первый запрос: count = 5, PATCH {"count": "count+1"} → count = 6
// Второй запрос: count = 6, PATCH {"count": "count+1"} → count = 7

// Установка значения (идемпотентно)
// Первый запрос: PATCH {"name": "John"} → name = "John"
// Второй запрос: PATCH {"name": "John"} → name = "John"

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

Используй PUT когда:

  • Нужно заменить весь ресурс целиком
  • Есть все данные ресурса
  • Нужна идемпотентность
  • Редко в REST API
// Замена всего документа
http.put('api/users/123', body: completeUserObject);

Используй PATCH когда:

  • Нужно обновить только часть ресурса
  • Есть только те данные, которые меняются
  • Хочешь избежать потери данных
  • Большинство обновлений (99% случаев)
// Обновить только имя
http.patch('api/users/123', body: jsonEncode({'name': 'New Name'}));

// Обновить несколько полей
http.patch('api/users/123', body: jsonEncode({
  'name': 'New Name',
  'email': 'new@example.com',
}));

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

                    PUT                 PATCH
──────────────────────────────────────────────
Семантика           Замена целиком      Обновление части
Емкость данных      Весь ресурс         Только изменения
Идемпотентность     Да (всегда)         Зависит
Риск потери данных  Высокий             Нет
Бандвидт            Больше              Меньше
Успех                200 OK              200 OK
                    204 No Content      204 No Content
Ошибка              400, 404, 409       400, 404
Употребление        Редко               Часто

HTTP коды ответов

// 200 OK — обновление успешно, вернуть обновленный ресурс
response.statusCode == 200

// 204 No Content — обновление успешно, но тело не возвращаем
response.statusCode == 204

// 400 Bad Request — некорректные данные
response.statusCode == 400

// 404 Not Found — ресурс не найден
response.statusCode == 404

// 409 Conflict — конфликт версий (для PUT часто)
response.statusCode == 409

Best Practices для Flutter

// ✅ Используй PATCH по умолчанию
async {
  await http.patch(
    Uri.parse('https://api.example.com/users/$id'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode(updateData),
  );
}

// ✅ Собирай только изменённые поля
final updateData = <String, dynamic>{};
if (newEmail != null) updateData['email'] = newEmail;
if (newName != null) updateData['name'] = newName;

// ❌ Избегай отправки пустых значений
body: jsonEncode({
  'email': null, // Плохо!
  'phone': '', // Плохо!
})

// ✅ Используй PUT только для полной замены
// (на практике это редко нужно)

Вывод

  • PUT — замена ресурса целиком, требует отправки всех данных
  • PATCH — обновление части ресурса, отправляешь только изменения
  • В большинстве случаев (95%+) используй PATCH
  • PATCH безопаснее (меньше риск потери данных)
  • PATCH экономнее (меньше данных отправляется)

Для Flutter приложений: используй PATCH по умолчанию, PUT только когда нужна полная замена ресурса.