Чому метод PATCH не є безсильним?


48

Мені це було цікаво.

Припустимо, у мене є userресурс з idі nameполями. Якщо я хочу оновити поле, я можу просто зробити запит PATCH на такий ресурс

PATCH /users/42
{"name": "john doe"} 

І тоді додаток оновить ім'я користувача 42.

Але чому, якщо я повторюю це прохання, результат був би іншим?

За даними RFC 5789

PATCH не є ні безпечним, ні безсильним


що робити, якщо між викликами хтось інший робить запит на оновлення користувача 42{"name": "bendjamin franklin"}
gnat

@gnat не має подібного аргументу також для методу PUT, який замість цього вважається ідентичним? (див. goo.gl/t24ZSJ )
mattecapu

"PUT має ідентичну семантику і тому може бути безпечно використаний для абсолютних оновлень (тобто ми надсилаємо весь стан ресурсу на сервер), але не і для відносних оновлень (тобто ми надсилаємо лише зміни до стану ресурсу) , оскільки це буде порушувати його семантика ... "( POST та PUT запити - це просто конвенція? )
gnat

1
Очевидно ... Але можна сказати, що PUT не є ідентичним, тому що між двома рівними запитами другий клієнт може зробити третій запит між двома, але оскільки попередні дані нам не цікаві, це не проблема. Той самий аргумент стосується запитів PATCH.
mattecapu

2
Я зважився додати посилання на відповідну специфікацію, оскільки вважаю це дуже актуальним у контексті цього питання.
Піт

Відповіді:


34

Запит PATCH може бути ідентичним, але цього не потрібно. Саме тому її характеризують як неідентичну.

Чи PATCH може бути ідентичним або ні, сильно залежить від того, як повідомляються необхідні зміни.
Наприклад, якщо формат патчу у формі {change: 'Name' from: 'benjamin franklin' to: 'john doe'}, то будь-який запит PATCH після першого буде мати інший ефект (відповідь на відмову), ніж перший запит.
Іншою причиною неідентифікації можливостей може бути те, що застосування модифікації на чомусь іншому, ніж оригінальний ресурс, може зробити ресурс недійсним. Тоді так само буде, якщо ви застосуєте зміну кілька разів.


3
Я не розумію останнього абзацу, чи можете ви навести приклад того, як "застосування модифікації на чомусь іншому, ніж оригінальний ресурс може зробити ресурс недійсним", і як це стосується застосування декількох разів зміни до одного ресурсу?
Робін Грін

3
@RobinGreen: Припустимо, що ресурс представлений у XML з вимогою, що існує максимум один <name>елемент. Якщо PATCH додає <name>елемент до ресурсу, який спочатку не містив його, то застосування PATCH двічі (або застосування його до ресурсу, який вже містить a <name>) робить ресурс недійсним, оскільки він раптом містить два <name>елементи, які не дозволені за такі ресурси.
Барт ван Інген Шенау

13
Перший приклад, який ви навели, не стосується IMHO, оскільки він безсильний. Приклад із DELETE, який є idempotent, перший запит: ресурс існував, але був видалений (повертається 2xx), другий запит: ресурс не існує і досі не існує після запиту, повертається 4xx. Стан сервера не змінився, таким чином, idempotency. У вашому прикладі, перший запит: PATCH від BenFra до JohDoe, ім'я ресурсу було BenFra, але зараз це JohDoe (повертається 2xx), другий запит: PATCH від BenFra до JohDoe, ім'я ресурсу було JohDoe і досі є JohDoe (повертається 4xx). Отже, це не показує, що PATCH може бути несильним.
sp00m

Детальніше тут: stackoverflow.com/q/4088350/1225328
sp00m

8

Я думаю, що чіткою відповіддю, коли PATCH у неідентичному, є цей абзац із RFC 5789:

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

Оскільки RFC вказує, що патч містить деякі "загальні зміни" ресурсу, нам слід виходити за рамки просто типової заміни поля. Якщо ресурс призначений для лічильника, то патч може вимагати його збільшення, що явно не є idempotet.


2

PATCHзапити описують набір операцій, які слід застосувати до ресурсу, якщо ви застосовуєте один і той же набір операцій двічі до одного ресурсу, результат може бути не однаковим. Це пояснюється тим, що визначати операції залежить від вас. Іншими словами, ви повинні визначити правила злиття .

Пам'ятайте, що PATCHзапит може використовуватися для виправлення ресурсів у багатьох різних форматах, а не лише JSON.

Таким чином, PATCHзапит може бути ідентичним, якщо ви визначаєте правила злиття як ідентичні .

Ідентичний приклад:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  age: 33
}

// New resource
{
  name: 'Tito',
  age: 33
}

Неідентичний приклад:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  $increment: 'age'
}

// New resource
{
  name: 'Tito',
  age: 33
}

У другому прикладі я використав синтаксис "схожий на монго", який я створив для збільшення атрибута. Зрозуміло, що це не є ідентичним, оскільки надсилання одного і того ж запиту кілька разів призводить до різних результатів кожного разу.

Тепер вам може бути цікаво, чи правильно використовувати такий складений синтаксис. Відповідно до стандартів , це:

Різниця між запитами PUT та PATCH відображається в тому, як сервер обробляє додану сутність для зміни ресурсу, визначеного Request-URI. У запиті PUT вкладений об'єкт вважається модифікованою версією ресурсу, що зберігається на початковому сервері, і клієнт вимагає замінити збережену версію. Однак із PATCH додане об'єднання містить набір інструкцій, що описують, як ресурс, що перебуває в даний час на початковому сервері, повинен бути модифікований для створення нової версії.

І вам також може бути цікаво, чи спокійно використовувати PATCHзапити таким чином, і багато людей вважають, що їх немає, ось хороша відповідь з великою кількістю коментарів щодо цього питання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.