Конвенція REST URI - сингулярне або множинне найменування ресурсу під час його створення


529

Я новачок у REST, і я помітив, що в деяких службах RESTful вони використовують різні URI ресурсів для оновлення / отримання / видалення та створення. Як от

  • Створення - використання / ресурсів методом POST (спостерігайте за множиною) в деяких місцях, використовуючи / resource (однина)
  • Оновлення - за допомогою / ресурсу / 123 методом PUT
  • Отримати - Використання / resource / 123 методом GET

Мене трохи не бентежить ця конвенція іменування URI. Що ми повинні використовувати множину чи однину для створення ресурсів? Якими мають бути критерії при вирішенні цього?


9
Після цієї теми я зібрав декілька прикладів відомих API REST у статті: inmensosofa.blogspot.com/2011/10/… .
jjmontes

3
Висновок, до якого я дійшов, прочитавши всі відповіді нижче: Завжди використовуйте однину, оскільки (а) це послідовно, (б) він відображає безпосередньо назви однини класів та таблиць, (в) деякі множинні іменники є неправильними (непередбачуваними) англійською мовою
Will Sheppard

Дивіться цю відповідь за посиланням на конвенції про іменування єдиної таблиці, і є ще одна стаття, в якій згадується саме ця проблема Ділема розробника API відпочинкового API - дякую @Sorter
Буде Шеппард

Відповіді:


281

Передумова використання /resourcesполягає в тому, що він представляє "всі" ресурси. Якщо ви зробите це GET /resources, ви, ймовірно, повернете всю колекцію. Відправивши на/resources , ви додаєте до колекції.

Однак окремі ресурси доступні на / ресурсі. Якщо ви зробите це GET /resource, ви, ймовірно, помилитесь, оскільки цей запит не має сенсу, тоді як/resource/123 має ідеальний сенс.

Використання /resourceзамість /resourcesподібне тому, як ви це зробили, якби працювали, скажімо, з файловою системою та колекцією файлів і /resourceє "каталогом" з особою 123, 456файлами в ній.

Жоден спосіб не є правильним чи неправильним, ідіть із тим, що вам найбільше подобається.


55
Чудова відповідь! Але каталоги "за замовчуванням" у Windows мають множинні назви. Як-от "Файли програм", "Користувачі", "Документи", "Відео" тощо. Також я часто частіше зустрічаю імена множини в URL-адресах веб-сайтів.
Дмитро Гончар

50
Конвенція про дефакто дуже багато людей і API, які приймають там, - це зберігати їх у множині завжди. Ідентифікатори вказують ОДИН ресурс автомобілі / id
PositiveGuy

205
"Жоден спосіб не є правильним чи неправильним. Вибирайте те, що вам найбільше подобається." Ах знаменита лінія, яку я чую так часто, і мені нудно слухати людей. Конвенції мають значення і ОБОВ'ЯЗКОВО слід обговорювати конструктивно серед громади, саме тут вживаються кращі рішення та передовий досвід. Коли ви використовуєте як і множину, так і однину для імен ресурсів в URI, це ускладнює ваш код і API, оскільки користувач і код, що стоїть за API, повинні враховувати це в маршрутах і логіці для диференціювання одиничного від множини, тоді як якщо ви просто дотримуєтеся з множиною весь час у вас немає проблем.
PositiveGuy

30
@TomaszPluskiewicz Ви абсолютно праві, що клієнтів не хвилює. Як розробників програмного забезпечення нам слід подбати - і для цього я погоджуюся з коментарем WTF про те, що конструктивні дискусії щодо конвенції є цінними.
Травіс Д

12
Тож хтось може просто відповісти одним словом і прийняти це, тому мені не доведеться все це читати (ще раз).
Бен Джордж

623

Для мене краще мати схему, яку можна відображати безпосередньо в коді (легко автоматизувати), головним чином тому, що код - це те, що буде на обох кінцях.

GET  /orders          <---> orders 
POST /orders          <---> orders.push(data)
GET  /orders/1        <---> orders[1]
PUT  /orders/1        <---> orders[1] = data
GET  /orders/1/lines  <---> orders[1].lines
POST /orders/1/lines  <---> orders[1].lines.push(data) 

22
Складність або простота цього пов'язана з недотриманням HATEOS. Не має значення, чи множина, однина чи щось інше. Ви повинні поважати відправлені урі з сервера, а не "збирати" свої урі на клієнті. Тоді у вас є 0 карт для виконання вашого коду.
Річард

7
@richard Клієнт все ще повинен зробити картування. У HATEOS їм доведеться зіставити ім'я, яке представляє відношення (відносність) до конструкції URI. Потім відношення, метод (дієслово) та Content-Type складають ресурс носія. Це не виключає необхідності гарного дизайну URI. Навіть незважаючи на те, що клієнт може віддавати перевагу назві rel, розробникам API все ще потрібен хороший для людини читати стандарт для побудови URI.

4
На мій погляд, це краща відповідь. За винятком того, що я завжди вважав за краще використовувати однину замість множини. User.getList (), User.getById, User.delete тощо
Eastern Monk

3
Мені подобається простота. Картографування також має перевагу в тому, щоб зробити документацію та тести на маршрутах написати неймовірно просто.
delos

5
Це має для мене сенс. Однак ми - це магазин, що займається базою даних, тобто ми генеруємо об'єкти коду та api з нашої схеми баз даних. І стандарти бази даних, як правило, пропонують особливі назви таблиць, тому ми йдемо з цим, але все ще за тією ж логікою, що і ця відповідь.
Андре К. Андерсен

274

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


69
Це найкраща відповідь, що стосується мене. Я вдячний тим, що дизайнерам API подобається мовна правильність висловлювання "отримати ресурс № 123", але це зайві проблеми з кодуванням при написанні клієнтів API, а також довідкової документації. (GET / api / люди проти GET / api / person / 123? Euuuchh.) .... замість того, щоб думати про це як "отримати ресурс № 123", фразувати це в голові як "отримати з колекції ресурсів, які матчі №123 ".
Warren Rumak

5
Розрізняти множинні / однинні ресурси - це не мовна правильність, а масштабність. / Співробітники / 12 читає мені як підмножину ресурсу співробітників з id '12' (це може означати що завгодно, наприклад, збережений пошуковий запит нещодавно звільнених працівників). Якщо ви читаєте вище як працівник з ідентифікатором "12", як би ви представляли підмножину? Єдиний варіант полягає в тому, щоб зробити більш складні рудні колекції URI, що містять об'єкти від самих об'єктів (тобто однини проти множини).
Ерік

9
Вибір / співробітників / 12 для відображення пошукового запиту щодо нещодавно звільнених працівників (або будь-якого підмножини), я думаю, поганий дизайн. Якщо ви хочете представляти підмножини будь-якого типу, я пропоную представити їх як ресурси (із власними іменами) самостійно.
Ян Дейнхард

3
Це не має нічого спільного з зрозумілістю для клієнтів. Йдеться про вирішення різних речей з різними URL-адресами. І вміти реагувати на всі методи HTTP, не конфліктуючи. Ви можете мати ресурс, що представляє собою сукупність предметів, і ресурс, який представляє сам предмет. Мені все одно, що ресурс колекції може бути example.org/166316e2-e1і одним конкретним елементом у цій колекції example.org/20d68348-ccc-001c4200de . Клієнт не повинен створювати URL-адреси (що, очевидно, не масштабує, це не RESTful, і саме для цього використовуються типи зв’язків).
Ерік

4
Якщо ви не вважаєте, що довільні URL-адреси є гарними, сміливо ідентифікуйте ресурс колекції з іменем множини та окремим елементом з особливим іменем. Якщо вам не подобаються англійські URL-адреси, і ваша натуральна мова не підтримує такий спосіб позначення однини / множини, використовуйте щось інше, щоб визначити це на своїй бажаній мові, я вважаю, що всі мови дозволяють вам якось розрізнити '/ the-collection-of- bla / 2321 'проти' bla / 61 'у письмовій формі. І кожен з цих двох різних ресурсів представляє абсолютно різні результати при надсиланні GET / PUT / DELETE / POST / PATCH та інших.
Ерік

77

Множина

  • Простий - усі URL-адреси починаються з одного префікса
  • Логічний -orders/ отримує індексний список замовлень.
  • Стандарт - Найпоширеніший стандарт, за яким слідує переважна більшість державних та приватних API.

Наприклад:

GET /resources - повертає список елементів ресурсу

POST /resources - створює один або кілька елементів ресурсу

PUT /resources - оновлює один або кілька елементів ресурсу

PATCH /resources - частково оновлює один або кілька елементів ресурсу

DELETE /resources - видаляє всі елементи ресурсу

І для окремих елементів ресурсу:

GET /resources/:id- повертає конкретний елемент ресурсу на основі :idпараметра

POST /resources/:id - створює один ресурсний елемент із заданим ідентифікатором (вимагає перевірки)

PUT /resources/:id - оновлення конкретного ресурсного елемента

PATCH /resources/:id - частково оновлює конкретний ресурсний елемент

DELETE /resources/:id - видаляє певний ресурсний елемент

Захисникам однини, подумайте про це так: Ви б попросили когось orderі очікували одне, або список речей? То чому ви очікуєте, що сервіс поверне список речей під час введення /order?


10
Сингулярне : У випадку, коли частина вашої системи є лише одним об’єктом (0-1, існує чи ні), наприклад, користувачі / 1 / аватар, ви можете використовувати особливу форму для позначення цього єдиного об'єкта (наприклад, аватара) - більш детальний приклад тут: stackoverflow .com / a / 38296217/860099 . BTW - дуже приємна відповідь :)
Kamil Kiełczewski

Як щодо відображення назв класів та таблиць, які мають бути єдиними? (див. іншу відповідь )
Буде Шеппард

@WillSheppard - Назви класів найкращі в однині, а назви таблиць - у формі множини. Наприклад Order, хороше ім’я для класу, який займається поодинокими екземплярами об'єктів, що відносяться до одного порядку. OrderList- назва класу, який має справу з декількома Orderекземплярами. Orders Table- це гарне ім’я для таблиці баз даних багатьох замовлень.
Ерік Кнудтсон

Я хочу отримати / замовлення, але я хочу лише / 1
jim smith

@ jim-smith, то чому б ти не вимагаєш / 1 з колекції користувачів з GET / users / 1?
Ромер

49

Однини

Зручність У речах можуть бути неправильні назви множини. Іноді їх немає. Але сингулярні імена завжди є.

наприклад, Адреса клієнта через адреси клієнта

Розглянемо цей пов'язаний ресурс.

Це /order/12/orderdetail/12читабельніше і логічніше, ніж/orders/12/orderdetails/4 .

Таблиці баз даних

Ресурс представляє сутність, як таблиця бази даних. Вона повинна мати логічну назву однини. Ось відповідь над назвами таблиць.

Картографування класів

Заняття завжди поодинокі. Інструменти ORM генерують таблиці з тими ж іменами, що імена класів. По мірі використання все більшої кількості інструментів однини назви стають еталоном.

Детальніше про дилему розробника API REST API


39
Сингулярні імена завжди є /clothe/12/trouser/34 :)
Герт Арнольд,

18
@GertArnold слово clotheє дієсловом. API відпочинку в основному дотримуються іменників, коли говорять про ресурси та використовують дієслова при описі дій. Форма однини є clout, але є архаїчною і, ймовірно, буде більш доцільною заміною на garment.
Стів Бузонас

@SteveBuzonas А для брюк і сонцезахисних окулярів?
Корай Тугай

32

У той час як найбільш поширеною практикою є RESTful apis, де використовуються множини, наприклад /api/resources/123, є один особливий випадок, коли я вважаю, що вживання однини називається більш підходящим / виразним, ніж назви множини. Це справа стосунків один на один. Зокрема, якщо цільовим елементом є об'єкт значення (у парадигмі дизайну, керованого доменом).

Припустимо, що кожен ресурс має індивідуальний, accessLogякий може бути змодельований як об'єкт значення, тобто не сутність, тому немає ідентифікатора. Це можна виразити як /api/resources/123/accessLog. Звичайні дієслова (POST, PUT, DELETE, GET) належним чином виразили б намір, а також факт, що відносини справді є один на один.


4
Хороша спроба. Але це було б краще як "accessLogEntries". :-)
Том Расселл

8
@TomRussell чому? Наслідки цього важливі. Я розумію, чому ви б використовували множину, навіть коли ви звертаєтесь до ресурсу за допомогою ідентифікатора, але для багатьох-до-одного чи один-до-одного це цілком оману. Розглянемо програму, яка керує співробітниками багаторазової компанії. Кожен співробітник працює в одному місці. GET /users/123/locationповинен отримати місцезнаходження, в якому працює користувач. Чи GET /users/123/locationsнасправді не вводить в оману споживача?
Керрі Кендалл

1
@CarrieKendall Я бачу вашу думку. Оскільки accessLogмоделюється як атрибут або значення, а не сутність, воно має бути єдиним. Якщо вам надається надмірна інженерія, то запис у журналі буде сутністю, і у вас є /api/accessLogEntries?resource=123.
Том Рассел

Погодився, хоча, я думаю, це порушує конвенцію про плюралізацію всіх речей. Це хитро. Для мене важливо, ніж API бути прямим, тобто документація повинна доповнювати вже пряму реалізацію.
Керрі Кендалл

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

26

Чому б не дотримуватися поширеної тенденції імен таблиць баз даних, де сингулярна форма загальновизнана? Був там, зробив це - давайте повторно використовувати.

Таблиця іменування дилеми: однини проти множини


8
Das Auto набагато кращий, ніж Die Autos. Також англійські конвенції про множину не узгоджуються.
FlavorScape

7
Простір імен ресурсів - це питання семантики, а не реалізації. Тож, використовуючи аналоги таблиць БД, не дуже пощастило. Також під час роботи з DB-іми ви маніпулюєте лише таблицями, хоча, звичайно, ви можете впливати на вміст (рядки), але в REST немає обмежень безпосередньо маніпулювати одним ресурсом.
arpadf

3
Я думаю, що це хороша аналогія, але важливіше, ніж вирішувати, чи йти в однині чи множині, - це відповідати тому, що ви вибрали. Ви не збираєтеся вставляти в Користувачів, а потім вибираєте з Користувача. Це ж правило має застосовуватися і до ресурсів REST - не перейменуйте їх залежно від того, що ви робите.
Тод Меньє

3
Це не лише назви таблиць, але й порівнянні з іменами класів в ОО (мій клас називався б "Клієнт не клієнти").
bytedev

У цьому випадку семантика є надто важливою, щоб просто прийняти "вже визначені" тенденції
Каттані Сімоне

19

Я здивований, побачивши, що так багато людей стрибне на множині іменника bandwagon. Виконуючи перетворення однини в множину, чи піклуєтесь ви про іррегулярні іменники множини? Вам подобається біль?

Дивіться http://web2.uvcs.uvic.ca/elc/studyzone/330/grammar/irrplu.htm

Існує багато типів неправильної множини, але такі найпоширеніші:

Тип іменника Утворення множини Приклад

Ends with -fe   Change f to v then Add -s   
    knife   knives 
    life   lives 
    wife   wives
Ends with -f    Change f to v then Add -es  
    half   halves 
    wolf   wolves
    loaf   loaves
Ends with -o    Add -es 
    potato   potatoes
    tomato   tomatoes
    volcano   volcanoes
Ends with -us   Change -us to -i    
    cactus   cacti
    nucleus   nuclei
    focus   foci
Ends with -is   Change -is to -es   
    analysis   analyses
    crisis   crises
    thesis   theses
Ends with -on   Change -on to -a    
    phenomenon   phenomena
    criterion   criteria
ALL KINDS   Change the vowel or Change the word or Add a different ending   
     man   men
     foot   feet
     child   children
     person   people
     tooth   teeth
     mouse   mice
 Unchanging Singular and plural are the same    
     sheep deer fish (sometimes)

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

1
Є англійські слова, які є нерегулярними до того, що часто виникає проблема навіть в англосфері, і вони часто використовуються такі терміни, як індекс / індекси / індекси, вертикс / вертикси / вершини, матриця / матриці / матриці, радіус / радіуси / радіусів і т. д. Я не бачу сенсу робити шляхи REST множинними, оскільки якщо вони всі послідовно однини, це для всіх просто очевидніше.
чорт

@kishorborate, Використання множини як URI більш схильне до помилок, навіть для носіїв англійської мови. Як дедд вказує, множини, такі як індекс / індекси / індекси, створюють більше проблем. І є незлічувані іменники. Змішування незлічуваних іменників із множиною - ще одна проблема. Чому програмістам важче витрачати більше часу на це? Я пропоную використовувати сингули для всього. Якщо є / {id}, API повинен повернути один запис. Якщо немає / {id}, що випливає далі, API повинен повернути колекцію.
Дам Фу

3
Сингулярний ресурс @DamingFu не завжди може мати з ним асоційований ідентифікатор. напр. / user / {id} / nickName Подивившись на нього, не зрозуміло, чи поверне він список nickNames чи єдиний nickName? Отже, API більш інтуїтивно зрозумілі, коли він використовує множинні форми. Так, кілька слів матимуть неправильні множинні форми. Для когось, хто читає форму множини, це не проблема. Це питання лише під час написання підпису API. Але частота таких слів невисока, також пошук множини будь-якого слова не займає багато часу. Ми повинні погодитися, щоб зробити API більш інтуїтивно зрозумілими.
кишорський борат

15

З точки зору споживача API, кінцеві точки повинні бути передбачуваними

В ідеалі ...

  1. GET /resources повинен повернути список ресурсів.
  2. GET /resource повинен повернути код рівня 400 рівнів.
  3. GET /resources/id/{resourceId} повинен повернути колекцію з одним ресурсом.
  4. GET /resource/id/{resourceId} повинен повернути ресурсний об'єкт.
  5. POST /resources повинні створювати ресурси.
  6. POST /resource повинен створити ресурс.
  7. PUT /resource повинен оновити ресурсний об’єкт.
  8. PATCH /resource слід оновити ресурс, розмістивши лише змінені атрибути.
  9. PATCH /resources повинен пакетно оновлювати ресурси, розміщуючи лише змінені атрибути.
  10. DELETE /resourcesслід видалити всі ресурси; жартую: 400 код статусу
  11. DELETE /resource/id/{resourceId}

Цей підхід є найбільш гнучким і багатим на особливості, але також вимагає найбільшого часу, щоб розвиватись. Отже, якщо ви поспішаєте (що завжди має місце при розробці програмного забезпечення), просто назвіть свою кінцеву точку resourceабо форму множини resources. Я вважаю за краще форма однини, тому що вона дає вам можливість самоаналізу та оцінювання програмно, оскільки не всі форми множини закінчуються на "s".

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

Деякі критерії прийняття рішення можуть бути:

  1. Які мої часові обмеження?
  2. Які операції я дозволятиму своїм споживачам?
  3. Як виглядає запит та корисна навантаження?
  4. Чи хочу я мати можливість використовувати відображення та розбирати URI у своєму коді?

Отже, це залежить від вас. Тільки, що ви робите, будьте послідовними.


1
Схоже, форма множини була обрана тому, що розробники, здається, припускають, що всі ресурси по суті є частиною якоїсь колекції. Однак "прийнята умова", схоже, вказує на те, що POST /usersслід створити єдиного користувача, додавши його до колекції. Я не погоджуюсь. POST /usersслід створити список користувачів (навіть якщо це список 1), де як POST /userслід створити саме одного користувача. Я не бачу жодної причини, через яку не можуть існувати як множинні, так і єдині кінцеві точки ресурсу. Вони описують різні способи поведінки, і нікого не слід дивувати їх функцією.
розчавити

Чи не існує домовленості щодо визначення ідентифікатора ресурсу на шляху? Якщо це так, то, здається, його багато нехтують. Наприклад, POST users/<id>створив би нового користувача.
Том Расселл

1
@TomRussell зазвичай сервер створює ідентифікатор, тому ви ще не знали ідентифікатора в POST.
Олексій

3
@TomRussell, коли клієнт визначає (своєрідний) ідентифікатор під час створення нового ресурсу, його частіше використовувати PUT /users/<id>замість POST. POSTмає тлумачення "додати це до колекції та визначити ідентифікатор як частину цього". PUTмає тлумачення "оновити (або додати) цей ресурс за допомогою цього ідентифікатора." Див. Restcookbook.com/HTTP%20Methods/put-vs-post для більш тривалого пояснення цього принципу.
Йохем Шуленклоппер

Я не вважаю, що порівняння з API Twitters є справедливим, оскільки вони використовують форму множини для всіх своїх кінцевих точок. Вони не змішують множину та однину для одних і тих же Елементів.
Ендрю Т Фіннелл

7

Мої два центи: методи, які проводять свій час, змінюючи від множини до однини або навпаки, - це марність циклів процесора. Я, можливо, старенька школа, але в мої часи подібні речі називали однаковими. Як шукати методи щодо людей? Жодна регулярна експресія не охопить і людини, і людей без небажаних побічних ефектів.

Англійські множини можуть бути дуже довільними, і вони обтяжують код без потреби. Дотримуйтесь однієї конвенції про іменування. Комп'ютерні мови повинні були говорити про математичну ясність, а не про наслідування природній мові.


2
Це адресний код, який намагається "автоматично генерувати / маніпулювати" кінцеві точки (є багато бібліотек, що вважають себе впевненими, які припускають множинність / сингулярність і намагаються скласти карту); однак це стосується явно вибраних назв кінцевих точок більше, ніж вибору потрібного слова (незалежно від того, як воно множиться).
користувач2864740

6

Я вважаю за краще використовувати особливу форму як для простоти, так і для послідовності.

Наприклад, враховуючи таку URL-адресу:

/ замовник / 1

Я буду ставитися до клієнта як до колекції клієнтів, але для простоти частина колекції видаляється.

Ще один приклад:

/ обладнання / 1

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


2
POST / замовник здається, що він замінить одного і єдиного клієнта. Це моє найбільше горе з використанням єдиних імен ресурсів.
Ендрю Т Фіннелл

2
@ andrew-t-finnell Не POST /customerповинен робити саме це - вставити одного клієнта?
donmutti

Він вставляє єдиного Клієнта в колекцію клієнтів. POST /customerчитає мені так, ніби це ПОСЛІД для theклієнта. Не колекція клієнтів. Однак я визнаю, що множина чи ні множина є перевагою. Поки вони не змішані, як у інших відповідях. Це було б неймовірно заплутано.
Ендрю Т Фіннелл

"Розміщення замовника" в цьому випадку не має сенсу. POST не замінює, він вставляє. Можливо, якби це був POST / customer / 1, я міг би бачити дилему, але навіть це не має великого сенсу з точки зору REST, адже що ви вставляєте? Було б / замовник / 1 / рахунок-фактура або / замовник / 1 / квитанція тощо
чорт

5

Ідентифікатор у маршруті повинен розглядатися так само, як і індекс до списку, і іменування має здійснюватися відповідно.

numbers = [1, 2, 3]

numbers            GET /numbers
numbers[1]         GET /numbers/1
numbers.push(4)    POST /numbers
numbers[1] = 23    UPDATE /numbers/1

Але деякі ресурси не використовують ідентифікатори в своїх маршрутах, тому що існує лише один, або користувач ніколи не має доступу до більш ніж одного, тому вони не є списками:

GET /dashboard
DELETE /session
POST /login
GET /users/{:id}/profile
UPDATE /users/{:id}/profile

4

З умовами іменування, як правило, сміливо сказати «просто вибрати один і дотримуватися його», що має сенс.

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

І в цьому контексті лінгвістичні правила можуть отримати вас лише в наступному:

Каталог може містити кілька файлів та / або підкаталогів, і тому його ім'я має бути у множині.

І мені це подобається.
Хоча, з іншого боку - це ваш каталог, ви можете назвати його "a-resource-or-multiple-resources", якщо саме цього ви хочете. Це насправді не головне.

Важливо те, що якщо ви помістили файл з назвою "123" під каталог з назвою "resourceS" (в результаті /resourceS/123), ви не зможете очікувати, що він буде доступний через /resource/123.

Не намагайтеся зробити його розумнішим, ніж це має бути - перехід від множини до сингулярного залежно від кількості ресурсів, до яких Ви зараз отримуєте доступ, може бути естетично приємним для деяких, але це не ефективно і це не має сенсу в ієрархічна система.

Примітка: Технічно ви можете робити "символічні посилання", так що до них /resources/123також можна отримати доступ /resource/123, але перше все ж має існувати!


3

Ознайомтеся з керівництвом Google по дизайну API: Імена ресурсів для інших взяти на себе називають ресурсах.

Коротко:

  • Колекції називають множиною.
  • Окремі ресурси названі рядком.
|--------------------------+---------------+-------------------+---------------+--------------|
| API Service Name         | Collection ID | Resource ID       | Collection ID | Resource ID  |
|--------------------------+---------------+-------------------+---------------+--------------|
| //mail.googleapis.com    | /users        | /name@example.com | /settings     | /customFrom  |
| //storage.googleapis.com | /buckets      | /bucket-id        | /objects      | /object-id   |
|--------------------------+---------------+-------------------+---------------+--------------|

Варто прочитати, якщо ви думаєте про цю тему.


2

Використання множини для всіх методів є більш практичним принаймні в одному аспекті: якщо ви розробляєте та тестуєте API ресурсів за допомогою Postman (або подібного інструменту), вам не потрібно редагувати URI при переході з GET на PUT до POST тощо .


1
Це не аргумент для мене, оскільки Postman пропонує колекції, тому ви можете зберегти всі ресурси як різні предмети колекції та перевірити їх окремо. Все, що ви робите - це вибір ресурсу з колекції, вам не потрібно щоразу редагувати параметри / методи / тощо.
Wirone

1

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

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

Якщо ви робите будь-яке глибоке посилання на представлення запитів щодо відносин, тоді розробникам, які пишуть проти вашого API, можна допомогти, дотримуючись суворішої угоди.

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

Припустимо, у нас є така модель.

interface User {
    <string>id;
    <Friend[]>friends;
    <Manager>user;
}

interface Friend {
    <string>id;
    <User>user;
    ...<<friendship specific props>>
}

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

GET /users/{id}/friends/{friendId}/manager

Нижче наведено ще кілька прикладів:

  • GET /users - перелічити користувацькі ресурси в глобальній колекції користувачів
  • POST /users - створити нового користувача у світовій колекції користувачів
  • GET /users/{id} - отримання конкретного користувача із світової колекції користувачів
  • GET /users/{id}/manager - отримати менеджера конкретного користувача
  • GET /users/{id}/friends - отримати список друзів користувача
  • GET /users/{id}/friends/{friendId} - отримати конкретного друга користувача
  • LINK /users/{id}/friends - додати до цього користувача асоціацію друзів
  • UNLINK /users/{id}/friends - видалити асоціацію друзів у цього користувача

Зауважте, як кожен рівень відображається з батьком, на який можна діяти. Використання різних батьків для одного і того ж об’єкта є протиінтуїтивним. Отримання ресурсу не GET /resource/123залишає жодних ознак того, що створення нового ресурсу слід робити наPOST /resources


1

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

Як щодо обох? І маючи на увазі, я маю на увазі використання однини для всього API, а потім створювати маршрути для переадресації запитів, зроблених у множині, до форми однини. Наприклад:

GET  /resources     =     GET  /resource
GET  /resources/1   =     GET  /resource/1
POST /resources/1   =     POST /resource/1
...

Ви отримуєте картину. Ніхто не помиляється, мінімальні зусилля, і клієнт завжди буде правильно.


1
Якщо ви робите 302 переадресації, а ваш кеш зберігає все двічі, ви неправильно налаштували кеш. Кеш не повинен зберігати 302 переадресації.
wynnset

2
Якщо клієнт завжди використовує /resourcesі завжди переспрямовується /resource, ви зробили це неправильно. Якщо хтось інший використовує ваш API, він може або використовувати правильну URL-адресу безпосередньо, або бути перенаправлений (що працює, але неправильно), і саме ви відкрили неправильний шлях.
maaartinus

Не впевнений, що ви маєте на увазі "неправильно" - це дуже суб'єктивно. Це насправді не так, тому що це працює.
wynnset

Це збільшує вартість обслуговування, а також вартість розуміння та кількість необхідного коду.
Буде Шеппард

1

Мені не подобається бачити {id}частину URL-адрес, що перекриваються субресурсами, якid теоретично може бути чим завгодно, і буде двозначність. Це змішування різних понять (ідентифікатори та назви субресурсів).

Подібні проблеми часто спостерігаються в enumконстантах або структурах папок, де різні поняття змішані (наприклад, коли у вас є папки Tigers,Lions і Cheetahs, а також папка, яка називається Animalsна одному рівні - це не має сенсу, оскільки один є підмножиною інший).

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

Отже, кінцеві точки, які стосуються одного користувача:

GET  /user             -> Not allowed, 400
GET  /user/{id}        -> Returns user with given id
POST /user             -> Creates a new user
PUT  /user/{id}        -> Updates user with given id
DELETE /user/{id}      -> Deletes user with given id

Потім є окремий ресурс для запитів користувачів, який, як правило, повертає список:

GET /users             -> Lists all users, optionally filtered by way of parameters
GET /users/new?since=x -> Gets all users that are new since a specific time
GET /users/top?max=x   -> Gets top X active users

Ось кілька прикладів субресурсу, який стосується конкретного користувача:

GET /user/{id}/friends -> Returns a list of friends of given user

Подружись (посилання багато на багато):

PUT /user/{id}/friend/{id}     -> Befriends two users
DELETE /user/{id}/friend/{id}  -> Unfriends two users
GET /user/{id}/friend/{id}     -> Gets status of friendship between two users

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


1

Використовуйте Singular і скористайтеся англійською конвенцією, що міститься в напр. "Бізнес-довідник".

Багато речей читають так: "Книжковий кейс", "Собака пачок", "Художня галерея", "Кінофестиваль", "Автомобільна партія" тощо.

Це зручно відповідає URL-адресі зліва направо. Тип предмета зліва. Встановити тип справа.

Чи GET /usersсправді коли-небудь забирає набір користувачів? Не зазвичай. Він отримує набір заглушок, що містять ключ і, можливо, ім’я користувача. Так що це насправді не так /users. Це індекс користувачів, або "індекс користувача", якщо ви хочете. Чому б не назвати це? Це /user/index. Оскільки ми назвали тип набору, ми можемо мати кілька типів, що показують різні проекції користувача, не вдаючись до параметрів запиту, наприклад, user/phone-listабо /user/mailing-list.

А що з користувачем 300? Це все ще /user/300.

GET /user/index
GET /user/{id}

POST /user
PUT /user/{id}

DELETE /user/{id}

На завершення, HTTP може мати коли-небудь відповідь на один запит. Шлях завжди посилається на одне особливе.


-1

Для мене множини маніпулюють колекцією , тоді як сингли маніпулюють предметом всередині цієї колекції.

Колекція дозволяє методам GET / POST / DELETE

Пункт дозволяє способи GET / PUT / DELETE

Наприклад

POST в / студенти додадуть нового учня в школу.

DELETE on / учні видалять усіх учнів школи.

DELETE on / student / 123 видалить студента 123 зі школи.

Це може здатися неважливим, але деякі інженери іноді забувають ідентифікатор. Якщо маршрут завжди був множинним і виконував DELETE, ви можете випадково стерти свої дані. Якщо відсутній ідентифікатор в однині поверне 404 маршрут, не знайдений.

Для подальшого розширення прикладу, якщо API повинен був виставити кілька шкіл, то щось подібне

DELETE on / school / abc / students видалить усіх учнів у школі abc.

Вибір правильного слова іноді є складним завданням самостійно, але мені подобається підтримувати множинність колекції. Наприклад, cart_itemsчи cart/itemsпочуваєш себе правильно. На відміну від видалення cart, видаляє об'єкт кошика сам, а не предмети в кошику;).


Чи не слід це все-таки розділити / кошик та / кошик / предмет (и)? Тоді ви можете адресувати весь кошик (наприклад, із видаленням) або окремі елементи?
Роб Грант

@RobertGrant Хіба це не "/ візки / предмети / 123"? (напр., чому "кошик", а не "візок" - це правило "завжди множина"?)
user2864740

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

хтось коли-небудь створив би кінцеву точку, яка просто видаляє всю колекцію? Мені здається надзвичайно небезпечним, і, мабуть, також, чому REST насправді не підтримує пакетні делети. (вам доведеться загортати масив в об’єкт). Якби мені абсолютно потрібна кінцева точка, щоб видалити цілу колекцію, я би переконався, що URI був дуже дуже унікальним і, безумовно, не схожим на POST
cnps

-1

Як щодо:

/resource/(не /resource)

/resource/ означає, що папка містить щось, що називається "ресурс", це папка "повторне використання".

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


-2

Я вважаю за краще використовувати як множину ( /resources), так і однину ( /resource/{id}), тому що вважаю, що це більш чітко розмежовує логіку між роботою над збиранням ресурсів і роботою над одним ресурсом.

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

GET /resources?Id=123

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

З іншого боку, при використанні форми однини:

GET /resource?Id=123

сервер, швидше за все, поверне помилку, оскільки ідентифікатор не вказаний належним чином, і користувачеві доведеться усвідомити, що щось не так.


1
Чому ви тут змішуєте ідіоми? Ви використовуєте належне позначення URI у першому абзаці, а потім переходите до параметрів запиту? Використання параметрів запиту для отримання ресурсу з ідентифікатором 123 тут повністю відсутнє.
Ендрю Т Фіннелл

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

Після того, як мене знову зняли, я переглянув те, що написав, і зрозумів, що початковий пост був правильним. Моя думка полягала саме в тому, що якщо користувач робить неправильну справу, то використання множини + однини насправді дасть краще повідомлення про помилку, ніж використання лише множини.
pberggreen

Я все ще відчуваю, що це заплутує проблему. Ідея використання множини полягає в тому, що це колекція. А число в кінці - це індекс у колекції. Що робити, якщо ви GET / ресурс сам по собі? Використання множини та однини разом є досить заплутаним. Кажучи / ресурси / 123 говорить: Завантажте мій ресурс 123 у відро ресурсів.
Ендрю Т Фіннелл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.