HTTP PATCH является идемпотентным или неидемпотентным?

Я читал много мест, где HTTP Patch неидемпотентен. Может кто-нибудь объяснить мне, почему он неидемпотентен? Потому что согласно определению - идемпотентные методы могут или не могут изменять состояние ресурса, но повторные запросы не должны иметь дополнительных побочных эффектов после первого запроса. Как повторный запрос PATCH может изменить состояние ресурса?


person SSR    schedule 21.03.2015    source источник


Ответы (3)


В этом есть некоторая путаница. Метод PATCH не требуется, чтобы он был идемпотентным, в этом суть. Клиенты не могут предполагать, что их запросы PATCH будут идемпотентными, в отличие от PUT и GET.

Будет ли конкретная реализация идемпотентной или нет, обычно зависит от используемого алгоритма исправления, если таковой имеется. Например, плохая реализация, в которой не используется формат сравнения, который проверяет текущие значения, не будет идемпотентным.

person Pedro Werneck    schedule 21.03.2015
comment
да. Приведенное выше объяснение имеет смысл. Спасибо за ответ :) - person SSR; 22.03.2015
comment
Извините, но вы можете делать не идемпотентные запросы PATCH даже с форматом сравнения, например JSON Patch. Например, добавляя элементы в массив: {"op": "add", "path": "/-", "value": "foo"} преобразует [] в ["foo"] в первый раз, затем в ["foo", "foo"] во второй раз, затем в ["foo", "foo", "foo"] в третий раз и т. Д. - person Maggyero; 11.02.2019
comment
@Maggyero не использует формат сравнения, который проверяет текущие значения - person Pedro Werneck; 12.02.2019
comment
Я не понимаю, как проверка соотносится с идемпотентностью. Добавление к массиву, проверено или нет, никогда не будет идемпотентным. - person Maggyero; 12.02.2019
comment
В самом деле, потому что добавление к массиву - это не операция, похожая на diff. - person Pedro Werneck; 16.02.2019
comment
Действительно? Как вы определяете операцию, похожую на diff, если вы исключаете операцию добавления? - person Maggyero; 20.02.2019

У меня есть сценарий, в котором PATCH не будет идемпотентным:

Предположим, два разных клиента отправляют HTTP-запросы.
Клиент X
Клиент Y

Клиент X
(1) ПАТЧ {"age": "10"}
response1-> {"age": "10", "sex": "f", "name ":" а "}

Клиент Y
(2) PATCH {"name": "b"}
response2-> {"age": "10", "sex": "f", "name ":" b "}

Клиент X
(3) PATCH {"age": "10"}
response3-> {"age": "10", "sex": "f", "name": "b"}

Вы можете видеть, что даже если запросы (1) и (3) одинаковы, ответы различаются. "name" в третьем ответе - "b".

Если это допустимый сценарий, это может быть доказательством того, что метод PATCH может отвечать разными ответами, даже если запросы одинаковы. Этого никогда не случится с методом PUT, который должен отправлять весь объект со всеми полями {возраст, пол, имя}.

person fascynacja    schedule 06.02.2018
comment
Идемпотентный запрос работает не так. Это манипулирование ресурсом на сервере, а не ответ. Подумайте о HTTP-запросе DELETE: когда вы вызываете N похожих запросов DELETE, первый запрос удалит ресурс, а ответ будет 200 (ОК) или 204 (Нет содержимого). Другие запросы N-1 вернут 404 (не найдено). Очевидно, что ответ отличается от первого запроса, но состояние любого ресурса на стороне сервера не изменяется, поскольку исходный ресурс уже удален. Итак, DELETE идемпотентен. - person brsfan; 20.03.2020
comment
мой пример доказывает, что: выполнение нескольких одинаковых запросов не имеет такого же эффекта, как выполнение одного запроса - person fascynacja; 20.03.2020

Да, есть много дискуссий и путаницы в том, чем отличаются PUT и PATCH. Ясно:

СТАВИТЬ

  • запрос должен содержать полное представление данного ресурса
  • идемпотентен (клиент может быть уверен на 100%)

ПЛАСТЫРЬ

  • запрос содержит только подмножество (только атрибуты, которые мы хотим обновить)
  • не обязательно быть идемпотентным (довольно часто идемпотентным, но это не правило, поэтому клиент не может быть в этом уверен на 100%)

Из этих правил мы можем вывести некоторые правила, которые нам нужно реализовать в бэкэнде, например:

a)

  • GET: пользователи / 1; тело ответа {username: 'john', email: '[email protected]'}
  • PUT: пользователи / 1; тело запроса {username: 'john'}

Либо ошибка проверки отправки из API (отсутствует email), либо электронное письмо будет удалено.

Я очень надеюсь, что API вернет ошибку проверки. Итак, чтобы удалить какое-то значение, клиент должен вызвать (явно email: null, упомянутый в запросе):

  • PUT: пользователи / 1; тело запроса {username: 'john', email: null}

b)

  • ПАТЧ: пользователи / 1; тело запроса {username: 'john'}

Никаких изменений на сервере. Чтобы удалить значение, клиент должен отправить:

  • ПАТЧ: пользователи / 1; тело запроса {email: null}

Оба приведенных выше примера идемпотентны.

В другом обсуждении приведен пример того, что PATCH неидемпотентен, если патч выполняет что-то вроде добавления в коллекцию в бэкэнде: Использование методов PUT и PATCH в реальных сценариях REST API

person sasynkamil    schedule 16.03.2021