Кращі практики для версії API? [зачинено]


877

Чи є відомі практичні вказівки чи найкращі практики для версії веб-сервісу REST API?

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

Відповіді:


682

Це хороше і хитре запитання. Тема дизайну URI є водночас найвизначнішою частиною API REST і , отже, потенційно довгостроковою прихильністю до користувачів цього API .

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

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

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

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

Крім того, оскільки вбудовування версії API в URI порушило б поняття гіпермедіа як двигуна стану додатків (зазначено в кандидатській дисертації Роя Т. Філдінгса), маючи адресу ресурсу / URI, які змінюватимуться з часом, я би зробив висновок, що API версії не повинні зберігатися в URI ресурсів протягом тривалого часу, тобто URI ресурсів, від яких можуть залежати користувачі API, повинні бути постійними посиланнями .

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

Кілька думок щодо обслуговування версій API, які мають на них термін придатності. Усі платформи / мови програмування, які зазвичай використовуються для реалізації веб-служб (Java, .NET, PHP, Perl, Rails тощо), дозволяють легко прив’язувати кінцеві точки веб-служб до базового URI. Таким чином легко збирати та зберігати колекцію файлів / класів / методів у різних версіях API .

Із POV користувачами API також простіше працювати та прив’язуватися до певної версії API, коли це очевидно, але лише обмежений час, тобто під час розробки.

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

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

Шляхом подолання цього розумного заперечення є реалізація останньої версії API під версією URI без версії API. У цьому випадку розробники клієнтів API можуть вибрати:

  • розробити проти останнього (зобов’язавшись підтримувати додаток, що захищає його від можливих змін API, які можуть порушити їх погано розроблений клієнт API ).

  • прив’язати до конкретної версії API (що стає очевидним), але лише на обмежений час

Наприклад, якщо API v3.0 є останньою версією API, наступні два мають бути псевдонімами (тобто поводитись однаково до всіх запитів API):

http: // shonzilla / api / customers / 1234 
http: // shonzilla / api /v3.0 / замовники / 1234
http: // shonzilla / api / v3 / customers / 1234

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

http: // shonzilla / api /v2.2 / замовники / 1234
http: // shonzilla / api /v2.0 / замовники / 1234
http: // shonzilla / api / v2 / замовники / 1234
http: // shonzilla / api /v1.1 / замовники / 1234
http: // shonzilla / api / v1 / замовники / 1234

повинен повернути будь-який з 30x кодів стану HTTP, які вказують на переспрямування , які використовуються разом із Locationзаголовком HTTP, який перенаправляє на відповідну версію URI ресурсу, яка залишається такою:

http: // shonzilla / api / замовники / 1234

Існують щонайменше два коди статусу HTTP перенаправлення, які відповідають сценаріям версії API:

  • 301 Переміщено постійно, вказуючи на те, що ресурс із запитуваним URI переміщений назавжди до іншого URI (який повинен бути постійною посиланням на екземпляр ресурсу, що не містить інформації про версію API). Цей код статусу може бути використаний для вказівки застарілої / непідтримуваної версії API, інформуючи клієнта API про те, що URI- версію, що переорієнтований, був замінений на постійну посилання на ресурс .

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

  • інші сценарії можна знайти в главі перенаправлення 3xx специфікації HTTP 1.1


142
Використання номера версії в URL-адресі не слід вважати поганою практикою, коли основна реалізація змінюється. "Коли інтерфейс до послуги змінюється не сумісним назад, насправді була створена абсолютно нова послуга ... З точки зору клієнта, сервіс - це не більше ніж інтерфейс і деякі нефункціональні якості." . Якщо інтерфейс до служби змінюється не сумісним назад, він більше не являє собою примірник оригінальної послуги, а є абсолютно новою послугою. " ibm.com/developerworks/webservices/library/ws-version
benvolioT

7
Чи є у вас думки щодо додавання заголовка з номером версії, щоб його можна було перевірити клієнтами або розробниками?
webclimber

11
Дивіться також використання заголовка Accept для позначення версії, яку очікує клієнт: blog.steveklabnik.com/2011/07/03/…
Weston Ruter

52
Останнє: Я б сказав, що застарілий і більше не підтримуваний API повинен повернутися 410 Gone, оскільки переспрямовування може вказувати на те, що нове місце є сумісним, коли його немає. Якщо API просто застарілий, але все ще існує, Warningможливим може бути заголовк HTTP у відповіді.
Michael Stum

22
Як ви маєте справу з клієнтами, які вже використовують стабільну URL-адресу, наприклад, shonzilla / api / customers / 1234, і ви хочете перейти на нову версію? як можна змусити їх додати до URL-адреси V2 (старий)?
Dejell

273

URL-адреса НЕ повинна містити версії. Версія не має нічого спільного з "уявленням" про ресурс, який ви запитуєте. Вам слід спробувати подумати про URL як про шлях до тієї концепції, яку ви хотіли б, - а не як ви хочете, щоб товар повертався. Версія диктує подання об’єкта, а не поняття об’єкта. Як говорили інші афіші, ви повинні вказати формат (включаючи версію) у заголовку запиту.

Якщо ви подивитесь на повний HTTP-запит на URL-адреси, які мають версії, це виглядає приблизно так:

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

Заголовок містить рядок, який містить представлення, про яке ви запитуєте ("Прийняти: application / xml"). Саме тут повинна піти версія. Кожен, здається, заморочує той факт, що ви можете хотіти одне й те саме в різних форматах і що клієнт повинен мати можливість запитати, що він хоче. У наведеному вище прикладі клієнт просить БУДЬ-які XML-представлення ресурсу - насправді не справжнє представлення того, що він хоче. Теоретично сервер міг повернути щось абсолютно не пов’язане із запитом, доки це XML, і його доведеться проаналізувати, щоб зрозуміти, що це неправильно.

Кращий спосіб:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

Далі скажімо, що клієнти вважають, що XML є занадто багатослівним, і тепер вони хочуть JSON. В інших прикладах вам доведеться мати нову URL-адресу для того ж клієнта, тож ви отримаєте:

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(або щось подібне). Насправді кожен запит HTTP містить потрібний формат:

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

Використовуючи цей метод, ви маєте набагато більше свободи в дизайні і фактично дотримуєтесь оригінальної ідеї REST. Ви можете змінювати версії, не порушуючи клієнтів, або поступово змінювати клієнтів, оскільки API змінюються. Якщо ви вирішите припинити підтримувати представлення, ви можете відповісти на запити кодом статусу HTTP або спеціальними кодами. Клієнт також може перевірити відповідь у правильному форматі та перевірити XML.

Є багато інших переваг, і деякі з них я обговорюю тут у своєму блозі: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Останній приклад, який показує, як неправильно вводити версію в URL. Скажімо, ви хочете отримати якусь інформацію всередині об’єкта, і ви переосмислили різні ваші об'єкти (клієнти - v3.0, замовлення - v2.0, а shipto - v4.2). Ось неприємна URL-адреса, яку ви повинні вказати клієнту:

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

10
Поводження з незалежною версією договору даних та версіями контрактів на обслуговування у заголовку Accept здається безладним настільки ж, наскільки це брудно в URL-адресі. Чи є інші варіанти? Крім того, якщо у мене є кілька кінцевих точок (мило, відпочинок), чи слід це також вказати в Accepts, і дозволити службі маршрутизації на кінці сервера визначати напрямок до правильної кінцевої точки АБО чи допустимо кінцеву точку кодувати в URL?
ideafountain

117
Я не можу погодитися з цим, принаймні, з точки зору вашої останньої причини. Це, мабуть, говорить про те, що різні частини URI мають різні версії. Але це не сенс версії API. Сенс у тому, щоб мати ОДНУ версію для цілого ресурсу. Якщо ви зміните версії, це інший ресурс API. Тому не має сенсу бачити company.com/api/v3.0/customer/123/v2.0/orders/4321, а скоріше company.com/api/v3.0/customer/123/orders/4321 Ви не модифікуєте жодну задану частину ресурсу, ви редагуєте ресурс у цілому.
crazy4jesus

90
Семантично використання номера версії в заголовку здається краще. Але набагато практичніше використання URL-адреси: менша схильність до помилок, найкраща налагодження, легко помічена розробниками, легко піддається модифікації під час тестування клієнтів відпочинку.
Даніель Серекедо

7
Я думаю, що BAD / DOBER над спрощує питання. API розшифровується як "Інтерфейс програмування додатків", а інтерфейси для версій здаються дуже хорошою ідеєю. API - це не лише обслуговування ресурсів. Що потрібно відокремити, це те, що деякі люди говорять про інтерфейси, а інші - про ресурси. Якщо ви уважно подивитеся на google maps api на вкладці мережі, ви побачите, що вони містять номер версії api в URL-адресі. Наприклад: maps.google.com/maps/api/jsv2 під час автентифікації. Jsv2 - це число api.
Том Грюнер

6
@Gili: Насправді, ви більше не повинні використовувати, -xоскільки це застаріло в RFC6648 .
Джонатан Ш

98

Ми вважаємо практичним і корисним розмістити версію в URL. Це дозволяє легко зрозуміти, що ви використовуєте з першого погляду. Ми робимо псевдонім / foo до / foo / (останні версії) для зручності використання, коротших / більш чистих URL-адрес тощо, як підказує прийнята відповідь.

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


5
Прийнята відповідь може бути правильною і найбільш чистою. Однак для розробника та щоденного користувача API цього, безумовно, найпростіший у використанні та налаштуваннях. Найпрагматичніший підхід. Як вказують інші Google та Amazon, також використовують цей підхід.
Мухаммед Рехан Саїд

46

Я погоджуюся, що редагування представлення ресурсів краще слідує підходу REST ... але, одна велика проблема зі спеціальними типами MIME (або типами MIME, які додають параметр версії), є поганою підтримкою для запису до заголовків Accept та Content-Type у HTML та JavaScript.

Наприклад, неможливо IMO для POST з такими заголовками у формах HTML5 для створення ресурсу:

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

Це відбувається тому , що HTML5 enctypeатрибут є перерахуванням, тому нічого, крім звичайних application/x-www-formurlencoded, multipart/form-dataі text/plainє недійсними.

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

Через це я зараз вважаю, що найбільш підходящим способом версії є URI, але я приймаю, що це не «правильний» спосіб.


14
Якщо припустити маршрут, в якому версії були визначені в заголовках, можна сказати, що HTML-форми, які використовують нативну форму, завжди використовуватимуть останню версію API, оскільки вони не переходять конкретну версію, якої хочуть дотримуватися. Однак запити XHR дійсно дозволяють вам змінювати приймання та читання заголовків типу вмісту. Тож основні форми - це справді єдина проблема.
Кайл Хейс

Я не впевнений, що я згоден з тим, що URI є найбільш підходящим, але той факт, що Content-Type не працює з формами, дуже важливий.
wprl

2
@Kyle, я десь побачив щоденник, в якому сказано, що якщо ви не вказали версію в заголовку запиту, найкраще повернутися з першою версією api, не останньою для найкращої сумісності.
Енді

Це насправді має багато сенсу для мене зараз, коли я думаю про це.
Кайл Хейс

@KyleHayes не забувайте iframes, video / embed та інші теги типу "src / href".
pllee

21

Помістіть свою версію в URI. Одна версія API не завжди підтримує типи з іншої, тому аргумент про те, що ресурси просто переносяться з однієї версії в іншу, є просто помилковим. Це не те саме, що перемикання формату з XML на JSON. Типи можуть не існувати або вони можуть змінитися семантично.

Версії є частиною адреси ресурсу. Ви здійснюєте маршрутизацію від одного API до іншого. Не хотіти приховувати адреси у заголовку.


13

Є кілька місць, де можна виконати версію в API REST:

  1. Як зазначалося, в URI. Це може бути простежено і навіть естетично приємно, якщо переспрямовування тощо подібне добре використовувати.

  2. У заголовку Accepts:, тому версія знаходиться у файлі файлів. Як і "mp3" vs "mp4". Це також буде працювати, хоча IMO працює трохи менше, ніж ...

  3. У самому ресурсі. У багатьох форматах файлів вбудовані номери версій, як правило, у заголовку; це дозволяє новішому програмному забезпеченню "просто працювати", розуміючи всі існуючі версії файлового типу, тоді як старіші програми можуть виправити, якщо вказана непідтримувана (новіша) версія. У контексті API REST це означає, що ваші URI ніколи не повинні змінюватись, а лише відповідь на конкретну версію даних, яку вам передали.

Я бачу причини використовувати всі три підходи:

  1. якщо вам подобається робити нові чисті API чи для великих змін версій, де вам потрібен такий підхід.
  2. якщо ви хочете, щоб клієнт дізнався перед тим, як зробити PUT / POST, чи буде він працювати чи ні.
  3. якщо це добре, якщо клієнт повинен виконати PUT / POST, щоб дізнатися, чи буде він працювати.

8

Версія API REST аналогічна версії будь-якого іншого API. Незначні зміни можуть бути зроблені на місці, а для великих змін може знадобитися зовсім новий API. Найпростіше для вас - починати з нуля кожен раз, що, коли введення версії в URL має найбільше сенс. Якщо ви хочете полегшити життя клієнту, ви намагаєтеся підтримувати зворотну сумісність, яку ви можете зробити з депрекацією (постійне переадресація), ресурсами в декількох версіях тощо. Це більш хитро і вимагає більше зусиль. Але це також те, що REST заохочує в "Класні URI не змінюються".

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

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