Допустимо ли использовать HTTP-метод PUT для обновления нескольких ресурсов одним запросом

Ответ

Технически это возможно реализовать, но это считается антипаттерном и нарушением семантики REST API.

Почему это плохая практика:

Метод PUT предназначен для полной замены ресурса по конкретному, известному URI. Он должен быть идемпотентным, то есть многократное выполнение одного и того же запроса должно приводить к одному и тому же состоянию ресурса.

При попытке обновить несколько ресурсов одним PUT-запросом возникают проблемы:

  1. Нарушение семантики: PUT работает с одним ресурсом. Например, PUT /users/123 заменяет пользователя с ID 123. Какой URI использовать для замены и пользователя, и продукта одновременно? PUT /batch-update семантически некорректен.
  2. Потеря идемпотентности: Если часть операции (например, обновление пользователя) пройдет успешно, а другая (обновление продукта) — нет, повторный запрос приведет к другому результату, нарушая принцип идемпотентности.
  3. Сложность обработки ошибок: Атомарность операции становится проблемой. Если один из объектов не удалось обновить, нужно ли откатывать остальные изменения?

Неправильный пример (как делать не надо):

# Этот запрос семантически неверен для PUT
PUT /api/resources
Content-Type: application/json

{
  "user": {"id": 1, "name": "Alice", "email": "alice@example.com"},
  "product": {"id": 42, "name": "Laptop", "price": 1200}
}

Рекомендация:

Для массовых или пакетных операций всегда используйте метод POST. Он специально предназначен для сценариев, которые не укладываются в простую CRUD-модель (GET, PUT, DELETE).

Ответ 18+ 🔞

А, слушай, смотри, вот тут такой вопрос подъехал — можно ли впихнуть обновление кучи разных сущностей в один PUT-запрос? Технически-то, конечно, можно, блядь, всё можно, если очень захотеть. Но это будет такой пиздец, такая архитектурная дичь, что потом сам себя в сраку засунешь, когда начнёшь это поддерживать.

Вот в чём, блядь, корень зла. Метод PUT — он же не просто так придуман. Он как молоток: один гвоздь — один удар. Он для полной замены одного конкретного ресурса, у которого есть свой чёткий адрес. И он должен быть идемпотентным, то есть сколько раз ни долби — результат один и тот же. Представь, ты пишешь одно и то же письмо сто раз — хуйня какая-то выходит, но в итоге в ящике лежит одно письмо, а не сто.

А теперь попробуй этим же молотком, блядь, сразу два гвоздя забить. Получается херня:

  1. Семантика летит в пизду. Какой URI ты укажешь? PUT /users/123 — понятно, это пользователь. А PUT /update-user-and-product — это уже не ресурс, а какая-то мартышлюшка, операция. PUT так не работает, ёпта!
  2. Идемпотентность накрывается медным тазом. Допустим, пользователя ты обновил, а продукт — нет, потому что цена отрицательная. Ты запрос повторил — а пользователя-то уже обновили! Оп, результат другой. Всё, приехали, принцип нарушен, пидары налетели.
  3. С ошибками ебаться до посинения. Один объект прошел, второй — нет. Что делать? Откатывать первого? А если нельзя? Короче, терпения ноль ебать, пока разберёшься.

Вот смотри, как делать НЕ НАДО, даже не думай:

# Этот запрос — чистой воды пиздопроебина. Не делай так!
PUT /api/resources
Content-Type: application/json

{
  "user": {"id": 1, "name": "Alice", "email": "alice@example.com"},
  "product": {"id": 42, "name": "Laptop", "price": 1200}
}

А как надо-то, спросишь?

Да всё просто, как три копейки! Для таких пакетных, хитрожопых операций есть же старый добрый POST. Он именно для этого и создан — делать что-то, что в простые рамки GET/PUT/DELETE не лезет.

Сделай себе нормальный эндпоинт для пакетных операций и шли туда POST-запрос. И спи спокойно. Всё по канону, все довольны, и совесть не гложет, как у того Герасима, блядь, после Муму.