ПРИМІТКА . Коли я вперше провів час, читаючи про REST, ідентифікація була заплутаною концепцією, щоб спробувати вийти правильно. У своїй оригінальній відповіді я все ще не зрозумів це правильно, як показали подальші коментарі (і відповідь Джейсона Хотгера ). Деякий час я чинив опір оновленню цієї відповіді, щоб уникнути ефективного плагіату Джейсона, але я зараз його редагую, бо, ну, мене просили (у коментарях).
Прочитавши мою відповідь, пропоную вам також прочитати відмінну відповідь Джейсона Хетгера на це запитання, і я спробую зробити свою відповідь кращою, не просто крадучись з Джейсоном.
Чому PUT ідентичний?
Як ви зазначали у вашому цитаті RFC 2616, PUT вважається безсильним. Коли ви PUT ресурс, ці два припущення відтворюються:
Ви посилаєтесь на сутність, а не на колекцію.
Суб'єкт, який ви постачаєте, є повним ( вся організація).
Давайте розглянемо один із ваших прикладів.
{ "username": "skwee357", "email": "skwee357@domain.com" }
Якщо ви надішліть цей документ /users
, як ви пропонуєте, ви можете повернути такий суб'єкт, як
## /users/1
{
"username": "skwee357",
"email": "skwee357@domain.com"
}
Якщо ви хочете змінити цю сутність пізніше, ви вибираєте між PUT та PATCH. PUT може виглядати так:
PUT /users/1
{
"username": "skwee357",
"email": "skwee357@gmail.com" // new email address
}
Це можна зробити за допомогою PATCH. Це може виглядати приблизно так:
PATCH /users/1
{
"email": "skwee357@gmail.com" // new email address
}
Ви відразу помітите різницю між цими двома. PUT включав усі параметри цього користувача, але PATCH включав лише той, що був змінений ( email
).
Під час використання PUT передбачається, що ви надсилаєте повну сутність, і ця повна сутність заміняється будь-яку існуючу сутність у цьому URI. У наведеному вище прикладі PUT та PATCH досягають однієї мети: вони обидва змінюють електронну адресу цього користувача. Але PUT обробляє його, замінюючи всю сутність, тоді як PATCH оновлює лише ті поля, які були поставлені, залишаючи інші в спокої.
Оскільки запити PUT включають всю сутність, якщо ви надсилаєте один і той же запит неодноразово, він завжди повинен мати однаковий результат (дані, надіслані вами, - це цілі дані сутності). Тому PUT є безсильним.
Неправильне використання PUT
Що станеться, якщо ви використовуєте вищезазначені дані PATCH у запиті PUT?
GET /users/1
{
"username": "skwee357",
"email": "skwee357@domain.com"
}
PUT /users/1
{
"email": "skwee357@gmail.com" // new email address
}
GET /users/1
{
"email": "skwee357@gmail.com" // new email address... and nothing else!
}
(Я припускаю, що для цього питання, що сервер не має певних обов'язкових полів, і дозволив би це статися ... це може бути не так у дійсності.)
Оскільки ми використовували PUT, але тільки постачали email
, то це єдине в цій сутності. Це призвело до втрати даних.
Цей приклад наведено для ілюстративних цілей - ніколи насправді цього не роби. Цей запит PUT є технічно бездоганним, але це не означає, що це не страшна, зламана ідея.
Як PATCH може бути безсильним?
У наведеному вище прикладі PATCH виявився безсильним. Ви внесли зміни, але якщо ви знову і знову вносили однакові зміни, це завжди призведе до того ж результату: ви змінили адресу електронної пошти на нове значення.
GET /users/1
{
"username": "skwee357",
"email": "skwee357@domain.com"
}
PATCH /users/1
{
"email": "skwee357@gmail.com" // new email address
}
GET /users/1
{
"username": "skwee357",
"email": "skwee357@gmail.com" // email address was changed
}
PATCH /users/1
{
"email": "skwee357@gmail.com" // new email address... again
}
GET /users/1
{
"username": "skwee357",
"email": "skwee357@gmail.com" // nothing changed since last GET
}
Мій оригінальний приклад, зафіксований на точність
Спочатку у мене були приклади, які, на мою думку, демонструють неідентичність, але вони вводили в оману / неправильно. Я буду тримати приклади, але використовую їх, щоб проілюструвати іншу річ: те, що декілька документів PATCH проти однієї сутності, змінюючи різні атрибути, не роблять PATCHes неідентичними.
Скажімо, що в якийсь минулий час було додано користувача. Це стан, з якого ви починаєте.
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@olddomain.com",
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "10001"
}
Після PATCH у вас є змінена сутність:
PATCH /users/1
{"email": "skwee357@newdomain.com"}
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@newdomain.com", // the email changed, yay!
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "10001"
}
Якщо потім кілька разів застосувати свій PATCH, ви будете отримувати той самий результат: електронний лист змінено на нове значення. А входить, А виходить, тому це безсильно.
Через годину, після того, як ви поїхали попити кави та перепочити, хтось ще приходить разом із власним ПАТЧЕМ. Здається, Поштове відділення внесло деякі зміни.
PATCH /users/1
{"zip": "12345"}
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@newdomain.com", // still the new email you set
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "12345" // and this change as well
}
Оскільки цей ПАТЧ з поштового відділення не стосується електронної пошти, лише поштовий індекс, якщо він повторно застосовується, він також отримає той самий результат: поштовий індекс встановлений на нове значення. А входить, А виходить, отже, це також безсильно.
Наступного дня ви знову вирішите надіслати свій ПАТЧ.
PATCH /users/1
{"email": "skwee357@newdomain.com"}
{
"id": 1,
"name": "Sam Kwee",
"email": "skwee357@newdomain.com",
"address": "123 Mockingbird Lane",
"city": "New York",
"state": "NY",
"zip": "12345"
}
Ваш патч має той самий ефект, що і вчора: він встановив електронну адресу. A зайшов, A вийшов, отже, і це безсильно.
Що я помилився у своїй оригінальній відповіді
Я хочу зробити важливу відмінність (щось я помилився в своїй оригінальній відповіді). Багато серверів відповідатимуть на ваші запити REST, надсилаючи назад новий стан сутності, з вашими модифікаціями (якщо такі є). Отже, коли ви отримаєте цю відповідь назад, вона відрізняється від тієї, яку ви отримали вчора , тому що поштовий індекс не той, який ви отримали востаннє. Однак ваш запит не стосувався поштового коду, лише електронної пошти. Таким чином, ваш документ PATCH все ще є ідентичним - електронний лист, який ви надіслали в PATCH, тепер є адресою електронної пошти для цієї особи.
Тож коли PATCH не є безсильним?
Для повного звернення до цього питання я знову звертаюсь до відповіді Джейсона Хотгера . Я просто збираюся залишити це на цьому, тому що я, чесно кажучи, не думаю, що зможу відповісти на цю частину краще, ніж він вже є.