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

Что такое PATCH?

1.3 Junior🔥 251 комментариев
#Сетевые протоколы и API

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

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

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

Что такое PATCH?

PATCH — это HTTP-метод (глагол), предназначенный для частичного обновления ресурса. В отличие от PUT, который предполагает полную замену ресурса, PATCH позволяет отправить только те изменения, которые необходимо применить к существующему ресурсу. Это делает его более эффективным и безопасным, особенно при работе с большими объектами или в сценариях, где несколько клиентов могут обновлять разные поля одного ресурса.

Основные характеристики PATCH

  • Частичное обновление: Используется для модификации отдельных полей или свойств ресурса, не затрагивая остальные.
  • Идемпотентность: По HTTP-спецификации (RFC 5789) PATCH не обязан быть идемпотентным (в отличие от PUT или DELETE). Однако на практике хорошим тоном считается проектировать PATCH-операции так, чтобы многократные одинаковые запросы приводили к одинаковому результату, что повышает надёжность.
  • Требует описания изменений: В теле запроса необходимо чётко указать, какие изменения применять. Это не просто "часть объекта", а инструкция для модификации.

Разница между PATCH, PUT и POST

  • POST: Создаёт новый ресурс. Обычно используется, когда идентификатор ресурса неизвестен или назначается сервером.
  • PUT: Полностью заменяет ресурс по указанному URI. Если ресурса нет, он может быть создан (зависит от реализации). Отправлять нужно полное представление ресурса.
  • PATCH: Частично модифицирует существующий ресурс по указанному URI. Отправляется только дельта — набор изменений.

Практическое применение в Go (Gin Framework)

В Go, при работе с веб-фреймворками (Gin, Echo, net/http), обработка PATCH-запроса выглядит аналогично обработке PUT или POST. Главное отличие — логика валидации и обновления данных на уровне приложения.

Рассмотрим пример с Gin для обновления профиля пользователя:

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name,omitempty"`
    Email string `json:"email,omitempty"`
    Age   int    `json:"age,omitempty"`
}

// In-memory хранилище для примера
var users = map[int]User{
    1: {ID: 1, Name: "Иван", Email: "ivan@example.com", Age: 30},
}

func main() {
    r := gin.Default()

    r.PATCH("/users/:id", patchUser)
    r.Run(":8080")
}

func patchUser(c *gin.Context) {
    id := c.Param("id")
    var userID int
    if _, err := fmt.Sscanf(id, "%d", &userID); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user ID"})
        return
    }

    // Ищем существующего пользователя
    existingUser, ok := users[userID]
    if !ok {
        c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
        return
    }

    // Частичное обновление: связываем только с теми полями, которые могут прийти
    var updateData map[string]interface{}
    if err := c.BindJSON(&updateData); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"})
        return
    }

    // Применяем изменения к существующей записи
    if name, ok := updateData["name"].(string); ok {
        existingUser.Name = name
    }
    if email, ok := updateData["email"].(string); ok {
        existingUser.Email = email
    }
    if age, ok := updateData["age"].(float64); ok { // JSON числа становятся float64
        existingUser.Age = int(age)
    }

    // Сохраняем обновлённого пользователя
    users[userID] = existingUser

    c.JSON(http.StatusOK, existingUser)
}

Форматы запросов PATCH

Сервер должен договориться с клиентом о формате инструкций для PATCH. Наиболее распространены:

  1. JSON Merge Patch (RFC 7396): Простой формат, где в теле запроса передаётся JSON-объект с полями, которые нужно изменить. Установка поля в null означает его удаление.

    // PATCH /users/1
    {"age": 31, "email": "new@example.com"}
    
  2. JSON Patch (RFC 6902): Более мощный и стандартизированный формат, использующий массив операций (add, remove, replace, move, copy, test).

    // PATCH /users/1
    [
      {"op": "replace", "path": "/age", "value": 31},
      {"op": "replace", "path": "/email", "value": "new@example.com"}
    ]
    

Ключевые преимущества использования PATCH

  • Эффективность передачи данных: Передаются только изменённые данные, что экономит трафик и уменьшает нагрузку на сеть.
  • Снижение риска конфликтов: Разные клиенты могут обновлять разные части одного ресурса, не перезаписывая изменения друг друга (при грамотной реализации логики).
  • Гибкость API: Позволяет создавать более точные и безопасные сценарии обновления.

Важные замечания для разработчика на Go

  • Валидация: При частичном обновлении критически важно валидировать входящие данные, особенно если используются указатели (omitempty) или структуры с частичным заполнением.
  • Транзакционность: PATCH-операция может включать несколько изменений. Желательно, чтобы они применялись атомарно (в рамках одной транзакции при работе с БД), чтобы избежать частичного обновления.
  • Версионирование API: При использовании PATCH важно документировать, какой формат изменений ожидается (например, JSON Merge Patch), и не менять его без версионирования эндпоинта.
  • Безопасность: Нельзя слепо применять входящие данные к модели. Всегда проверяйте права текущего пользователя на изменение тех или иных полей.

Таким образом, PATCH является мощным инструментом для построения эффективных, гибких и безопасных RESTful API, а его корректная реализация на Go требует внимания к деталям валидации, атомарности и формату передаваемых изменений.

Что такое PATCH? | PrepBro