Коли я можу використовувати параметри шляху та парами запитів у API RESTful?


141

Я хочу зробити свій RESTful API дуже передбачуваним. Яка найкраща практика для вирішення питання про те, коли зробити сегментацію даних за допомогою URI, а не використовувати параметри запитів.

Для мене має сенс, що системні параметри, які підтримують пагинацію, сортування та групування, мають бути після "?" А як щодо таких полів, як "статус" та "регіон" чи інші атрибути, які сегментують вашу колекцію? Якщо вони також мають бути параметри запитів, яке правило має знати про те, коли використовувати парами шляху?


1
аналогічне запитання відповідає тут ... stackoverflow.com/questions/3198492/…
Lalit Mehra

Відповіді:


239

Найкраща практика дизайну API RESTful полягає в тому, що параметри шляху використовуються для ідентифікації конкретного ресурсу або ресурсів, а параметри запитів використовуються для сортування / фільтрації цих ресурсів.

Ось приклад. Припустимо, ви реалізуєте кінцеві точки API RESTful для організації, яка називається Автомобіль. Ви структуруєте свої кінцеві точки так:

GET /cars
GET /cars/:id
POST /cars
PUT /cars/:id
DELETE/cars/:id

Таким чином, ви використовуєте лише параметри шляху, коли ви вказуєте, який ресурс отримати, але це ніяк не сортує / фільтрує ресурси.

Тепер припустимо, що ви хотіли додати можливість фільтрувати машини за кольором у своїх GET-запитах. Оскільки колір не є ресурсом (це властивість ресурсу), ви можете додати параметр запиту, який це робить. Ви додали б цей параметр запиту до свого GET-/cars запиту таким чином:

ЗАРАЗ /cars?color=blue

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

Що стосується синтаксису, то всі назви URL-адрес мають бути малими літерами. Якщо у вас є ім'я сутності, яке, як правило, два слова англійською мовою, ви використовуєте дефіс, щоб розділити слова, а не регістр верблюда.

Вих. /two-words


3
Дякую за вашу відповідь, Майк. Це чітка та проста методологія; вартий голосу від мене. І все ж часто розробники вибирають підхід "автомобілі / сині", мені цікаво, що їх міркують для цього ... можливо, вони вирішили зробити парами шляху для обов язкових полів, або, можливо, вони роблять це, щоб вказати, що база даних розділяється на цей фрагмент.
cosbor11

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

3
як щодо / автомобілі? id = 1 & color = синій замість автомобілів / 1 /? color = blue. ви в основному фільтруєте ресурси для автомобілів у кожному сценарії
mko

1
Неправильно, оскільки автомобіль з id 1 існує лише один, але машин із синім кольором може бути багато. Існує відмінність між особистістю та фільтром
Пауль

1
Моя гіпотеза про те, чому з використанням шляхом Params настільки широко поширене, тому що багато розробників , витягнуті з рамок , розроблених людьми , які не мають гарне уявлення про принципи REST (Ruby On Rails , зокрема.)
Chris Broski

58

Фундаментальний спосіб думати з цього приводу такий:

URI - це ідентифікатор ресурсу, який однозначно ідентифікує конкретний екземпляр ресурсу TYPE. Як і все в житті, кожен об'єкт (який є примірником якогось типу) має набір атрибутів, які є інваріантними або часовими.

У наведеному вище прикладі автомобіль - це дуже відчутний об’єкт, який має такі атрибути, як марка, модель та VIN - які ніколи не змінюються, а також колір, підвіска тощо, які можуть змінюватися з часом. Отже, якщо ми кодуємо URI атрибутами, які можуть змінюватися з часом (тимчасовими), ми можемо отримати кілька URI для одного об’єкта:

GET /cars/honda/civic/coupe/{vin}/{color=red}

І через роки, якщо колір цього самого автомобіля буде змінено на чорний:

GET /cars/honda/civic/coupe/{vin}/{color=black}

Зауважте, що сам автомобільний примірник (об’єкт) не змінився - змінився лише колір. Наявність декількох URI, що вказують на один і той же екземпляр об'єкта, змусить вас створити кілька обробників URI - це не ефективна конструкція, і, звичайно, не інтуїтивно зрозуміла.

Отже, URI повинен складатися лише з частин, які ніколи не змінюватимуться і надалі однозначно ідентифікуватимуть цей ресурс протягом усього життя. Все, що може змінитися, має бути зарезервовано для параметрів запиту як такого:

GET /cars/honda/civic/coupe/{vin}?color={black}

Підсумок - думайте про поліморфізм.


2
Цікава парадигма .. Це загальновживаний дизайн-паттен? Чи можете ви надати деякі API, які використовують це у своїй документації, або деякі посилання, що описують цю стратегію?
cosbor11

1
Мені подобається, як ви підкреслювали "TYPE", коли ви писали "URI - це ідентифікатор ресурсу, який однозначно ідентифікує конкретний екземпляр ресурсу TYPE". Я думаю, що це важлива відмінність.
jrahhali

15

У API REST ви не повинні надто перейматися передбачуваними URI. Сама пропозиція передбачуваності URI наводить на нерозуміння архітектури RESTful. Передбачається, що клієнт повинен будувати URI самі, чого вони насправді не повинні.

Однак я припускаю, що ви створюєте не справжній API REST, а API "REST натхненний" (наприклад, Google Drive). У цих випадках великим правилом є "парами шляху = ідентифікація ресурсу" та "параметри запиту = сортування ресурсів". Отже, виникає питання, чи можете ви однозначно визначити свій ресурс БЕЗ статусу / регіону? Якщо так, то, можливо, це параметр запиту. Якщо ні, то його параметр шляху.

HTH.


11
Я не згоден, хороший API повинен бути передбачуваним; ВІДПОВІДНО або іншим чином.
cosbor11

3
Я думаю так. Слід створити риму та причини, як формується URI, а не довільно називати кінцеві точки. Коли можна інтуїтивно написати клієнт API, не постійно посилаючись на документацію, ви, на мою думку, написали хороший API.
cosbor11

2
"Коли можна інтуїтивно написати клієнт API, не постійно посилаючись на документацію". Саме там, на мою думку, наше розуміння REST відрізняється ... клієнтові API ніколи не потрібно «збирати» URL-адресу. Вони повинні вибрати його у відповіді на попередній виклик API. Якщо ви сприймаєте веб-сайт як аналогію ... Ви переходите на facebook.com, ви вибираєте посилання на сторінку подій. Вам не байдуже, чи "передбачувана" URL-адреса у Facebook, як ви її не вводите. Ви потрапляєте туди через гіперпосилання. Те ж саме стосується і RIP api. Отже, зробіть URI, які мають значення для вас (сервера), але не го клієнта
Олівер Макфі

2
Додана примітка. Це не означає, що URI не повинні слідувати легко зрозумілому шаблону, це просто означає, що це не обмеження API RESTful. Найбільшою проблемою в цій області є люди, які припускають, що клієнт повинен створити URL-адреси самостійно. Вони не повинні, оскільки це створює зв'язок між клієнтом і сервером, який не повинен існувати. (наприклад, сервер не може змінити URL-адресу, не порушивши всі клієнтські програми). У API REST сервер може змінювати їх за власним бажанням.
Олівер Макфі

3
+1 для використання таких слів: "'парами шляху = ідентифікація ресурсу" та "параметри запиту = сортування ресурсів" ". Це справді розчистило це для мене.
Дуг

3

Одного разу я розробив API, головний ресурс якого був people. Зазвичай користувачі вимагають фільтрувати peopleтак, щоб не дозволяти користувачам викликати щось на зразок /people?settlement=urbanкожного разу, я реалізував, /people/urbanщо пізніше дозволило мені легко додавати /people/rural. Також це дозволяє отримати доступ до повного /peopleсписку, якщо згодом це буде корисно. Коротше кажучи, мої міркування полягали в тому, щоб додати шлях до загальних підмножин

Від сюди :

Псевдоніми для загальних запитів

Щоб зробити досвід API більш приємним для пересічного споживача, розгляньте упаковку наборів умов у легкодоступні маршрути RESTful. Наприклад, нещодавно закритий запит на квитки вище може бути упакований якGET /tickets/recently_closed


1

Взагалі кажучи, я схильний використовувати параметри шляху, коли в ресурсі є очевидна "ієрархія", наприклад:

/region/state/42

Якщо цей єдиний ресурс має статус, можна:

/region/state/42/status

Однак, якщо "регіон" насправді не є частиною експонованого ресурсу, він, ймовірно, належить до одного з параметрів запиту - подібного до пагинації (як ви згадали).


0

Сегментація є більш ієрархальною та "досить", але може бути обмежувальною.

Наприклад, якщо у вас URL-адреса з трьома сегментами, кожен проходить різні параметри для пошуку автомобіля за маркою, моделлю та кольором:

www.example.com/search/honda/civic/blue

Це дуже гарний URL і легше запам'ятовується кінцевим користувачем, але тепер ваш вид затримався з цією структурою. Скажіть, ви хочете зробити так, щоб у процесі пошуку користувач міг шукати ВСІ сині автомобілі чи ВСІ Хонда Громадяни? Параметр запиту вирішує це, оскільки він дає пару ключових значень. Так ви могли пройти:

www.example.com/search?color=blue
www.example.com/search?make=civic

Тепер у вас є спосіб посилатися на значення за допомогою його ключа - або "color", або "make" у вашому коді запиту.

Ви можете обійти це, можливо, використовуючи більше сегментів, щоб створити таку структуру ключових значень, як:

www.example.com/search/make/honda/model/civic/color/blue

Сподіваюся, що це має сенс ..


-2

Приклад URL: /rest/{keyword}

Ця URL-адреса є прикладом для параметрів шляху. Ми можемо отримати ці дані URL-адреси за допомогою @PathParam.

Приклад URL: /rest?keyword=java&limit=10

Ця URL-адреса є прикладом для параметрів запиту. Ми можемо отримати ці дані URL-адреси за допомогою @Queryparam.

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