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

Что делает PATCH в REST?

3.0 Senior🔥 61 комментариев
#Docker, Kubernetes и DevOps

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

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

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

PATCH метод в REST

PATCH — это HTTP метод для частичного обновления ресурса. Он отличается от PUT тем, что обновляет только те поля, которые были отправлены в запросе, без замены всего ресурса.

PATCH vs PUT

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

PUTполная замена ресурса. Если не отправить все поля, отсутствующие поля станут null или удалены.

// PUT запрос
PUT /api/users/123
{
  "name": "John"
}

// Результат: все другие поля удаляются/обнуляются
// User становится {id: 123, name: "John", email: null, age: null}

PATCHчастичное обновление. Обновляются только отправленные поля, остальное сохраняется.

// PATCH запрос
PATCH /api/users/123
{
  "name": "John"
}

// Результат: обновляется только name, остальные поля не меняются
// User остаётся {id: 123, name: "John", email: "old@email.com", age: 30}

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

Представим сущность User:

@Entity
@Table(name = "users")
public class User {
    @Id
    private Long id;
    private String name;
    private String email;
    private String phone;
    private LocalDate birthDate;
    private String city;
}

PUT — полная замена

@PutMapping("/{id}")
public ResponseEntity<User> updateUserFull(
    @PathVariable Long id,
    @RequestBody User updatedUser) {
    
    User user = userRepository.findById(id)
        .orElseThrow(() -> new NotFoundException("User not found"));
    
    // ПОЛНОЕ ПЕРЕЗАПИСЫВАНИЕ
    user.setName(updatedUser.getName());
    user.setEmail(updatedUser.getEmail());
    user.setPhone(updatedUser.getPhone());
    user.setBirthDate(updatedUser.getBirthDate());
    user.setCity(updatedUser.getCity());
    
    User saved = userRepository.save(user);
    return ResponseEntity.ok(saved);
}

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

@PatchMapping("/{id}")
public ResponseEntity<User> updateUserPartial(
    @PathVariable Long id,
    @RequestBody Map<String, Object> updates) {
    
    User user = userRepository.findById(id)
        .orElseThrow(() -> new NotFoundException("User not found"));
    
    // Обновляем ТОЛЬКО присутствующие поля
    updates.forEach((key, value) -> {
        switch(key) {
            case "name" -> user.setName((String) value);
            case "email" -> user.setEmail((String) value);
            case "phone" -> user.setPhone((String) value);
            case "birthDate" -> user.setBirthDate(
                LocalDate.parse((String) value));
            case "city" -> user.setCity((String) value);
        }
    });
    
    User saved = userRepository.save(user);
    return ResponseEntity.ok(saved);
}

Лучше — использование DTO с nullable полями

public class UserUpdateDto {
    @Nullable
    private String name;
    @Nullable
    private String email;
    @Nullable
    private String phone;
}

@PatchMapping("/{id}")
public ResponseEntity<User> updateUserPartial(
    @PathVariable Long id,
    @RequestBody UserUpdateDto updateDto) {
    
    User user = userRepository.findById(id)
        .orElseThrow(() -> new NotFoundException("User not found"));
    
    if (updateDto.getName() != null) {
        user.setName(updateDto.getName());
    }
    if (updateDto.getEmail() != null) {
        user.setEmail(updateDto.getEmail());
    }
    if (updateDto.getPhone() != null) {
        user.setPhone(updateDto.getPhone());
    }
    
    return ResponseEntity.ok(userRepository.save(user));
}

Или с JSON Patch (RFC 6902)

Для сложных операций используется стандартный JSON Patch формат:

// Запрос
PATCH /api/users/123
Content-Type: application/json-patch+json
[
  {"op": "replace", "path": "/name", "value": "John Doe"},
  {"op": "replace", "path": "/email", "value": "john@example.com"},
  {"op": "add", "path": "/phone", "value": "+1234567890"}
]

Реализация с JsonPatch (spring-boot-starter-json):

@PatchMapping("/{id}")
public ResponseEntity<User> updateUserWithJsonPatch(
    @PathVariable Long id,
    @RequestBody JsonNode patchNode) throws JsonPatchException {
    
    User user = userRepository.findById(id)
        .orElseThrow(() -> new NotFoundException("User not found"));
    
    JsonPatch patch = JsonPatch.fromJson(patchNode);
    ObjectMapper mapper = new ObjectMapper();
    
    JsonNode patched = patch.apply(
        mapper.convertValue(user, JsonNode.class));
    
    User updated = mapper.treeToValue(patched, User.class);
    return ResponseEntity.ok(userRepository.save(updated));
}

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

  • Частичные обновления — когда клиент обновляет только несколько полей
  • Экономия трафика — отправляется только изменённые данные
  • Снижение вероятности ошибок — не нужно отправлять все поля
  • Batch операции — обновление списка элементов с небольшими изменениями

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

  • Полная замена ресурса — когда нужно перезаписать весь объект
  • Идемпотентность — PUT гарантирует, что повторные запросы дают одинаковый результат
  • Создание ресурса — PUT может использоваться для создания с известным ID

Статус коды

  • 200 OK — обновление успешно, возвращаем обновленный ресурс
  • 204 No Content — обновление успешно, тело ответа не требуется
  • 400 Bad Request — неверные данные в запросе
  • 404 Not Found — ресурс не найден
  • 409 Conflict — конфликт версий (оптимистичная блокировка)

PATCH — это современный и эффективный способ частичного обновления ресурсов в REST API.