использует PUT с приемлемыми побочными эффектами (REST)

9

Я хочу создать историю отмен, когда пользователь обновляет форму. Поскольку это обновление, я хочу использовать запрос PUT. Тем не менее, я прочитал, что PUT не должен иметь побочных эффектов .

Допустимо ли здесь использовать PUT? Есть ли лучшие альтернативы?

PUT /person/F02E395A235

{
   time: 1234567,
   fields: {
      name: 'John',
      age: '41'
   }
}

На сервере

doPut('person/:personId',
   // create a new person snapshot
)

Редактировать:

История будет видна пользователю, вызов несколько раз приведет к нескольким версиям.

Решением было проверить, была ли версия уникальной перед ее созданием.

roo2
источник

Ответы:

11

Люди, разрабатывающие HTTP / 2, были гораздо более многословны в своих представлениях о том, что должен делать HTTP, сохраняя при этом старое значение. Давайте посмотрим, что спецификация проекта HTTP / 2 должна сказать об идемпотентности:

4.2.2. Идемпотентные методы

Метод запроса считается «идемпотентным», если предполагаемое воздействие на сервер нескольких идентичных запросов с помощью этого метода такое же, как влияние для одного такого запроса. Из методов запроса, определенных в этой спецификации, PUT, DELETE и безопасный запрос методы идемпотентны.

Как и определение сейфа, свойство идемпотента применяется только к тому, что было запрошено пользователем; сервер может регистрировать каждый запрос отдельно, сохранять историю контроля версий или реализовывать другие неидемпотентные побочные эффекты для каждого идемпотентного запроса .

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

То, что вы решили использовать ресурсы версии, здесь не имеет значения. Если вы не хотите создавать новую версию, когда ничего не изменилось, вам нужно сравнить полезную нагрузку в запросе PUT с самой последней (или иным образом идентифицированной) версией ресурса, и когда ни одно из свойств не изменилось Вы можете не создавать новую версию .


Ваше редактирование:

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

Что касается ресурса, то это не побочный эффект . Ресурс по этому URI не изменяется (те же свойства получают PUT). История - это просто метаданные, так как она, скорее всего, запрашивается другим URI или разными заголовками запроса.

CodeCaster
источник
Исключением является то, что вы отвечаете на мою конкретную проблему: «Допустимо ли для PUT создание истории, видимой пользователю», и дайте мне решение, спасибо
roo2
Для какой проблемы это решение? Что timeсвойство обновляется? Я думаю, что это тоже метаданные, даже если они есть в ресурсе.
CodeCaster
1
Проблема заключалась в том, что если было отправлено несколько PUT, пользователь получал бы длинную историю отмен с избыточной информацией. проверка на уникальность решает, что
roo2
12

HTTP различает два свойства:

  • идемпотентность
  • безопасности

Идемпотентность определяется спецификацией следующим образом:

Методы также могут иметь свойство " идемпотентности ", заключающееся в том, что (кроме ошибок с ошибками или истечением срока действия) побочные эффекты от N> 0 идентичных запросов такие же, как и для одного запроса. Методы GET, HEAD, PUTи DELETEобладают этим свойством. Кроме того, методы OPTIONSи TRACE НЕ ДОЛЖНЫ иметь побочных эффектов, и поэтому по своей природе идемпотентны.

И безопасность:

В частности, соглашение было установлено , что GETи HEADметоды НЕ ДОЛЖНО иметь значение принимает меры, кроме поиска. Эти методы следует считать « безопасными ». Это позволяет пользовательским агентам представлять другие методы, такие как POST, PUTи DELETE, особым образом, так, чтобы пользователь узнал о том, что запрашивается небезопасное действие.

Естественно, невозможно гарантировать, что сервер не генерирует побочные эффекты в результате выполнения GETзапроса; на самом деле, некоторые динамические ресурсы считают эту особенность. Важным отличием здесь является то, что пользователь не запрашивал побочные эффекты, поэтому не может нести за них ответственность.

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

Это помещает методы в три категории:

  • сейф (и , следовательно , также идемпотентная) GET, HEAD, OPTION,TRACE
  • идемпотентен но не всегда безопасно: PUT,DELETE
  • не идемпотентный и не безопасный POST

PUT не должен иметь побочных эффектов.

Это не правильно. PUTидемпотентен, но не безопасен. Весь смысл в PUTэто иметь побочный эффект, а именно обновление ресурса. То, что означает идемпотентность, заключается в том, что обновление одного и того же ресурса с одним и тем же содержимым несколько раз должно иметь тот же эффект, что и обновление его только один раз.

Обратите внимание на последний абзац в разделе о безопасности [выделено мной]:

Естественно, невозможно гарантировать, что сервер не генерирует побочные эффекты в результате выполнения GETзапроса; на самом деле, некоторые динамические ресурсы считают эту особенность. Важным отличием здесь является то, что пользователь не запрашивал побочные эффекты, поэтому не может нести за них ответственность .

Хотя в этом предложении говорится и о GETбезопасности, мы можем предположить, что авторы также намеревались применить те же рассуждения PUTи идемпотентность. IOW: PUTдолжен иметь только один видимый пользователю побочный эффект, а именно обновление названного ресурса. У него могут быть другие побочные эффекты, но пользователь не может нести за них ответственность.

Например, тот факт, что PUTидемпотентен, означает, что я могу повторить его так часто, как захочу: спецификация гарантирует, что выполнение его несколько раз будет точно таким же, как выполнение его один раз. Совершенно верно создать резерв старых версий как побочный эффект от этих многочисленных PUTзапросов. Однако, если в результате нескольких повторных попыток ваша база данных заполнится резервом старых версий, это не моя проблема, а ваша.

IOW: вам разрешено иметь столько побочных эффектов, сколько вы хотите, но

  1. он должен выглядеть для пользователя, как если бы его запросы были идемпотентными
  2. Вы несете ответственность за эти побочные эффекты, а не пользователь
Йорг Миттаг
источник
Да, идемпотентность - это состояние вставляемого ресурса, а не состояние какого-либо другого сервера / службы, на которое влияет действие PUT.
Марьян Венема
Upvote за отличное объяснение безопасности и идемпотентности в покое
roo2
Отличное объяснение. Тем не менее, вы делаете несколько утверждений, подобных этому: «Весь смысл в PUT - иметь побочный эффект, а именно обновление ресурса». Это кажется противоречием, если вы не подразумеваете под термином «побочный эффект» нечто иное, чем «нечто вторичное или непреднамеренное, которое происходит в дополнение к первичному, предполагаемому эффекту».
MarredCheese
@MarredCheese: я использую термин в его стандартном программном значении, которое в основном означает «любой« результат », который не является возвращаемым значением».
Йорг Миттаг
Ах, конечно. Благодарю за разъяснение.
MarredCheese
1

Вы правы, что у PUT не должно быть никаких побочных эффектов , однако я бы кое-что добавил к этому.

PUT не должен иметь побочных эффектов на ресурс, для которого выполняется эта операция PUT

Вы обновляете personресурс, который обозначен как F02E395A235, поэтому использование PUT является правильным. Теперь в качестве бизнес-правила вы также отслеживаете изменения, которые невидимы для вызывающего объекта (потребителя службы REST). Это не добавит новый элемент в personресурс. Исторический снимок не будет доступен с помощью /person/конечной точки. Поэтому я считаю, что PUT должен быть вполне приемлемым в этом случае.

Азиз Шейх
источник
1
Никаких побочных эффектов на размещаемый ресурс, но любое количество побочных эффектов на другие вещи (счетчики, ведение журнала, следы аудита, ...) вполне приемлемы.
Марьян Венема