RESTful API: HTTP-дієслова зі спільною або певною URL-адресою?


25

Створюючи API RESTful , чи слід використовувати HTTP Verbs за тією ж URL-адресою (коли це можливо) або я повинен створювати певну URL-адресу на дію?

Наприклад:

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

Або з певними URL-адресами, такими як:

GET     /items            # Read all items
GET     /item/:id         # Read one item
POST    /items/new        # Create a new item
PUT     /item/edit/:id    # Update one item
DELETE  /item/delete/:id  # Delete one item

Відповіді:


46

У останній схемі ви зберігаєте дієслова в URL-адресах своїх ресурсів. Цього слід уникати, оскільки для цієї мети слід використовувати дієслова HTTP. Прийміть базовий протокол замість того, щоб його ігнорувати, дублювати чи переосмислювати.

Подивіться DELETE /item/delete/:id, ви розміщуєте одну і ту ж інформацію двічі в одному запиті. Це зайве і цього слід уникати. Особисто я з цим плутаюсь. Чи підтримує API насправді DELETEзапити? Що робити, якщо я розміщую deleteURL-адресу та використовую замість іншого дієслова HTTP? Чи буде це відповідати чомусь? Якщо так, то кого обратимуть? Як клієнт належним чином розробленого API, мені не потрібно було задавати такі запитання.

Можливо, вам це потрібно, щоб якось підтримати клієнтів, які не можуть видавати DELETEчи PUTзапитувати. Якщо це так, я передаю цю інформацію у заголовку HTTP. Деякі API використовують X-HTTP-Method-Overrideзаголовки для цієї конкретної мети (що, на мою думку, все-таки є досить негарним). Я, звичайно, не розміщував би дієслова в стежках.

Ідіть на

GET     /items      # Read all items
GET     /items/:id  # Read one item
POST    /items      # Create a new item
PUT     /items/:id  # Update one item
DELETE  /items/:id  # Delete one item

Що стосується дієслів, це те, що вони вже чітко визначені в специфікації HTTP, а дотримання цих правил дозволяє використовувати кеші, проксі-сервери та, можливо, інші інструменти поза вашим додатком, які розуміють семантику HTTP, але не семантику вашого додатка. . Зауважте, що причина, коли вам слід уникати їх розміщення у своїх URL-адресах, полягає не в тому, що API RESTful вимагає читабельних URL-адрес. Йдеться про уникнення зайвої неоднозначності.

Більше того, API RESTful може відображати ці дієслова (або будь-який їх підмножина) на будь-який набір семантики додатків, якщо це не суперечить специфікації HTTP. Наприклад, цілком можливо побудувати RESTful API , який використовує тільки GET запити , якщо всі операції , які вона дозволяє є як сейф і ідемпотентів . Наведене вище відображення - лише приклад, який відповідає вашому використанню та відповідає вимогам. Це не обов'язково повинно бути таким.

Зауважте також, що по-справжньому API RESTful ніколи не вимагає від програміста читання великої документації про доступні URL-адреси, якщо ви відповідаєте принципу HATEOAS (Hypertext як двигун стану програми), що є одним із основних припущень REST . Посилання можуть бути абсолютно незрозумілими для людей, поки клієнтська програма може зрозуміти та використовувати їх для з'ясування можливих переходів стану додатків.


4
За відсутності PUTта DELETE, я вважаю за краще додати його до шляху, не диференціюючи його за рядком запиту. Це не зміна рядка запиту до існуючої операції; це окрема операція.
Роберт Харві

4
@RobertHarvey у такому випадку я б це все одно назвав рушником. Як ви кажете, це операція, і це не те, що я став би на шлях при розробці API, який має на меті бути RESTful. Розміщення його у рядку запиту просто здається менш інвазивним. Це запобігає кешування, але я не думаю, що відповіді на такі запити все одно не слід кешувати. Це також дозволяє споживачеві API легко вказувати метод без розбору та побудови URL-адреси. В ідеалі справді API RESTful повинен надавати гіперпосилання, не вимагаючи від клієнтів самостійно створювати URL-адреси.
toniedzwiedz

Якщо у вас немає всіх дієслів, це все одно не зовсім ВІДКРИТИ, чи не так?
Роберт Харві

@RobertHarvey правда, але я сприймаю їх як запасний варіант, а не як задуманий дизайн. Я думаю, що API повинен підтримувати фактичні методи HTTP, і якщо якийсь клієнт не може їх реалізувати з будь-якої причини, він може просто замінити їх використання на ці параметри запитів. Проксі-сервер навіть може захоплювати їх на ходу і перетворювати запити на запити, використовуючи справжні HTTP-дієслова, тому сервер навіть не потребує турботи. Небагато API навколо справді RESTful. Що стосується загальних веб-API, це справді справа смаку. Особисто я хотів би отримати чисті URL-адреси. Простіше зрозуміти ІМХО.
toniedzwiedz

1
@RobertHarvey, як пояснено, навряд чи призначений спосіб їх використання. Мені просто здається, що це менше, ніж два зла, коли вам доведеться подолати обмеження клієнтів. Я пам'ятаю, як читав документацію для такого API, але мені доведеться виконати деякий пошук в історії / закладках браузера, щоб знайти його. Тепер, коли я думаю про це, заголовок може бути кращим у цьому випадку. Чи погодились би ви?
toniedzwiedz

14

Перший.

URI / URL - це ідентифікатор ресурсу (натяк на назву: рівномірний ідентифікатор ресурсу). З першою умовою, ресурс, про який говорять, коли ви робите "GET / user / 123", і ресурс, про який говорять, коли ви робите "DELETE / user / 123", явно той самий ресурс, оскільки вони мають однакову URL-адресу.

З другою умовою ви не можете бути впевнені, що "GET / user / 123" і "DELETE / user / delete / 123" насправді є одним і тим же ресурсом, і, мабуть, це означає, що ви видаляєте пов'язаний ресурс, а не ресурс себе, тому було б досить дивно, що видалення /user/delete/123насправді видаляє /user/123. Якщо всі операції працюють над різними URL-адресами, URI більше не працює як ідентифікатор ресурсу.

Коли ви говорите DELETE /user/123, ви говорите "видалити" запис користувача з ідентифікатором 123 ". Хоча, якщо ви кажете DELETE /user/delete/123, те, що, здається, має на увазі, - це "видалити" запис делетора користувача з ідентифікатором 123 ", що, мабуть, не те, що ви хочете сказати. І навіть якщо ви використовуєте в цій ситуації більш правильне дієслово: "POST / user / delete / 123", в якому сказано: "зробіть операцію, додану до" делектора користувача з id 123 ", це все-таки круговий спосіб сказати видалити запис (це схоже на іменництво дієслова англійською мовою).

Один із способів ви можете думати про URL - це трактувати його як вказівники на об’єкти та ресурси як на об'єкти в об'єктно-орієнтованому програмуванні. Коли ви робите GET /user/123, DELETE /user/123ви можете думати , думати про них , як методи в об'єкті: [/user/123].get(), [/user/123].delete()де [], як покажчик разименованія оператора , але для URL - адрес (якщо ви знаєте мову, є покажчики). Одним з основних принципів REST є єдиний інтерфейс, тобто мати невеликий і обмежений набір дієслів / методів, який працює для всього у величезній мережі ресурсів / об’єктів.

Тому перший краще.

PS: звичайно, це дивиться на REST найчистішим чином. Іноді практичність перемагає чистоту, і вам потрібно піти на поступки мертвим клієнтам або каркасам, які ускладнюють правильний REST.


+1 для прикладу ООП :)
53777A

6

(вибачте, я вперше пропустив / редагувати / та / видалити / в (2) ...)

Ідея URI полягає в тому, що це ідентифікатор адресного ресурсу , а не виклик методу . Отже, URI повинен вказувати на конкретний ресурс. І якщо ви поважаєте URI, ви завжди повинні отримувати один і той же ресурс.

Тобто ви повинні думати про URI так само, як ви думаєте про Первинний ключ рядка в базі даних. Він однозначно ідентифікує щось: Універсальний ідентифікатор ресурсу.

Якщо ви використовуєте множину чи однину, URI повинен бути ідентифікатором, а не викликом . Що ви намагаєтеся зробити, це метод: GET (отримати), PUT (створити / оновити), DELETE (видалити) або POST (все інше).

Тож "/ item / delete / 123" ламає REST, оскільки він не вказує на ресурс, це скоріше виклик методу.

(Крім того, лише семантично ви маєте змогу отримати URI, вирішити, що він застарів, а потім ВИДАЛИТИ той самий URI - оскільки він є ідентифікатором. Якщо GET URI не має "/ delete /", а DELETE робить, то це суперечить семантиці HTTP. Ви транслюєте 2 або більше URI на ресурс, де буде 1.)

Тепер обман такий: немає реального чіткого визначення того, що є, а не ресурсу, тому загальним ухиленням у REST є визначення "іменника обробки" та вказівки на це URI. Це в значній мірі гра в слова, але вона задовольняє семантику.

Тож, якщо, наприклад, ви чомусь не могли використати це:

DELETE /items/123

Ви можете заявити всьому світу, що Ви маєте "делеторний" ресурс для обробки та використання

POST /items/deletor  { id: 123 }

Тепер це дуже схоже на RPC (віддалений виклик процедури), але він потрапляє через величезну лазівку пункту "обробка даних" специфікації POST, названого в специфікації HTTP.

Однак це робиться винятково, і якщо ви можете використовувати загальний PUT для створення / оновлення, DELETE для видалення та POST для додавання, створення та всього іншого, тоді вам слід , тому що це більш стандартне використання HTTP. Але якщо у вас є складний випадок на кшталт "здійснити" або "опублікувати" чи "редагувати", то випадок використання іменника процесора задовольняє пуристів REST і все ще надає вам потрібну вам семантику.

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