Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Для чего нужен PATCH?
PATCH — это HTTP метод для частичного обновления ресурса. Отличие от PUT в том, что PATCH меняет только те поля, которые указаны в запросе, тогда как PUT заменяет весь ресурс.
PATCH vs PUT — ключевая разница
Сценарий
Есть пользователь с этими данными:
{
"id": 1,
"name": "John Doe",
"email": "john@mail.com",
"age": 30,
"city": "New York"
}
Использование PUT (замена всего ресурса)
PUT /api/v1/users/1
Content-Type: application/json
{
"name": "Jane Doe",
"email": "jane@mail.com"
}
Результат: Ресурс ПОЛНОСТЬЮ заменяется. Поля age и city теряются!
{
"id": 1,
"name": "Jane Doe",
"email": "jane@mail.com",
"age": null,
"city": null
}
Использование PATCH (частичное обновление)
PATCH /api/v1/users/1
Content-Type: application/json
{
"name": "Jane Doe",
"email": "jane@mail.com"
}
Результат: Обновляются ТОЛЬКО указанные поля. Остальное остаётся неизменным!
{
"id": 1,
"name": "Jane Doe",
"email": "jane@mail.com",
"age": 30,
"city": "New York"
}
Сравнение HTTP методов
| Метод | Цель | Идемпотентность | Когда использовать |
|---|---|---|---|
| GET | Получить ресурс | ✓ Да | Чтение данных |
| POST | Создать ресурс | ✗ Нет | Создание новых данных |
| PUT | Заменить весь ресурс | ✓ Да | Полное обновление |
| PATCH | Обновить часть ресурса | ✓ Да | Частичное обновление |
| DELETE | Удалить ресурс | ✓ Да | Удаление данных |
Примеры использования PATCH
1. Обновление профиля пользователя
# Обновляем только город
PATCH /api/v1/users/1
Content-Type: application/json
{
"city": "Los Angeles"
}
2. Обновление статуса задачи
# Только меняем статус, остальное не трогаем
PATCH /api/v1/tasks/42
Content-Type: application/json
{
"status": "completed"
}
3. Обновление прав доступа
# Добавляем новую роль
PATCH /api/v1/users/100/roles
Content-Type: application/json
{
"add": ["admin"]
}
Реализация в Spring Boot
1. Controller с PATCH
import org.springframework.web.bind.annotation.*;
import org.springframework.http.HttpStatus;
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
private UserService userService;
// PATCH для частичного обновления
@PatchMapping("/{id}")
public ResponseEntity<UserDTO> partialUpdate(
@PathVariable Long id,
@RequestBody UserPatchDTO patchDTO
) {
UserDTO updated = userService.partialUpdate(id, patchDTO);
return ResponseEntity.ok(updated);
}
// PUT для полного обновления (для сравнения)
@PutMapping("/{id}")
public ResponseEntity<UserDTO> fullUpdate(
@PathVariable Long id,
@RequestBody UserDTO userDTO
) {
UserDTO updated = userService.fullUpdate(id, userDTO);
return ResponseEntity.ok(updated);
}
}
2. DTO для PATCH
// DTO для PATCH (все поля Optional)
public class UserPatchDTO {
private Optional<String> name;
private Optional<String> email;
private Optional<Integer> age;
private Optional<String> city;
// Getters/setters
}
// DTO для PUT (все поля обязательны)
public class UserDTO {
private String name;
private String email;
private Integer age;
private String city;
// Getters/setters
}
3. Service реализация
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// Частичное обновление (PATCH)
public UserDTO partialUpdate(Long id, UserPatchDTO patchDTO) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
// Обновляем ТОЛЬКО переданные поля
patchDTO.getName().ifPresent(user::setName);
patchDTO.getEmail().ifPresent(user::setEmail);
patchDTO.getAge().ifPresent(user::setAge);
patchDTO.getCity().ifPresent(user::setCity);
userRepository.save(user);
return toDTO(user);
}
// Полное обновление (PUT)
public UserDTO fullUpdate(Long id, UserDTO userDTO) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
// Заменяем ВСЕ поля
user.setName(userDTO.getName());
user.setEmail(userDTO.getEmail());
user.setAge(userDTO.getAge());
user.setCity(userDTO.getCity());
userRepository.save(user);
return toDTO(user);
}
}
JSON Merge Patch (RFC 7386)
Для PATCH часто используется стандарт JSON Merge Patch:
{
"name": "Jane",
"age": null // null = удалить это поле
}
JSON Patch (RFC 6902) — более сложный способ
[
{ "op": "replace", "path": "/name", "value": "Jane" },
{ "op": "remove", "path": "/age" },
{ "op": "add", "path": "/phone", "value": "+1234567890" }
]
Когда использовать PATCH
✓ Обновление отдельных полей — пользователь меняет только город
✓ Большие объекты — когда отправка всех данных затратна
✓ Частые небольшие обновления — статус, флаги, счётчики
✓ API, где клиент может знать только часть данных — мобильное приложение
✓ Исправление конкретных ошибок — клиент исправляет только ошибку
Когда использовать PUT
✓ Замена всего ресурса — загрузка полного профиля
✓ Когда нужна идемпотентность с гарантией — либо будут ВСЕ данные, либо старые
✓ Создание с известным ID — PUT может создать ресурс, если его нет
Идемпотентность
Оба метода идемпотентны:
- Несколько одинаковых PATCH запросов = результат как одного
- Несколько одинаковых PUT запросов = результат как одного
Вывод
PATCH нужен для частичного обновления ресурсов в REST API. Главное отличие от PUT:
- PATCH: обновляет только указанные поля
- PUT: заменяет весь ресурс
Выбирай PATCH, когда нужно обновить несколько полей из большого объекта. Используй PUT, когда нужна полная замена.