Як встановити REST URI


111

Який найкращий спосіб встановити RRI URI? В даний час ми маємо версію # в самому URI, тобто.

http://example.com/users/v4/1234/

для версії 4 цього представлення.

Чи належить версія в queryString? тобто.

http://example.com/users/1234?version=4

Або версію найкраще виконати іншим способом?


Відповіді:


34

Я б сказав, що зробити його частиною самого URI (варіант 1) найкраще, тому що v4 визначає інший ресурс, ніж v3. Параметри запиту, як у вашому другому варіанті, можна найкраще використовувати для передачі додаткової інформації (запиту), що стосується запиту , а не ресурсу .


11
Питання полягає в тому, чи це інший РЕСУРС, який ми обговорюємо? Або інше представлення цього ресурсу? Чи REST розрізняє представництво та ресурс?
Cheeso

1
@Cheeso - ОП вказує, що це інше представлення, а не інший ресурс, звідси і моя відповідь.
Грег Бук

На це відповіли більш детально, перш ніж тут stackoverflow.com/q/389169/104261
Тарас Аленін

+1 для "Параметри запиту, як у вашому другому варіанті, можна найкраще використовувати для передачі додаткової інформації (запиту), що стосується запиту, а не ресурсу"
Енді,

Для різних представлень, я думаю, вам слід використовувати заголовки типу "Прийняти", тоді клієнт може вказати серверу "Я приймаю лише версію 4", і сервер може відповісти з цим поданням. Якщо прийняття не надсилається, надається остання версія.
Карлос Вердес

190

Не версію URL-адрес, тому що ...

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

Якщо припустити, що ваш ресурс повертає певний варіант application / vnd.yourcompany.user + xml, все, що вам потрібно зробити, - це створити підтримку нового типу засобів масової інформації / vnd.yourcompany.userV2 + xml та за допомогою магії узгодження вмісту для вашого v1 та Клієнти v2 можуть співіснувати мирно.

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

URL-адреси, які клієнт використовує для взаємодії з сервером, повинні надаватися сервером, вбудованим у раніше отримані представлення. Єдина URL-адреса, яку повинен знати клієнт, - це коренева URL-адреса інтерфейсу. Додавання номерів версій до URL має значення лише в тому випадку, якщо ви створюєте URL-адреси на клієнті, що ви, мабуть, не робити з інтерфейсом RESTful.

Якщо вам потрібно внести зміни до типів ваших медіа, які порушать існуючих клієнтів, тоді створіть новий і залиште URL-адреси в спокої!

А для тих читачів, які зараз кажуть, що це не має сенсу, якщо я використовую application / xml та application / json як типи медіа. Як ми повинні їх версії? Ти не. Ці мультимедійні типи в значній мірі марні для RESTful інтерфейсу, якщо ви не розбираєте їх за допомогою завантаження коду, і тоді версія версії є суперечкою.


66
Щоб вирішити точки кулі. 1. Ви не перериваєте посилання на перму, тому що посилання на певну версію 2. Якщо все розроблено, це не проблема. Старі URL-адреси ще можуть працювати. В ідеалі, ви б не хотіли, щоб URL-версія версії 4 повертала асоціацію до ресурсу версії 3. 3. Можливо
Майк Поун

10
Уявіть, що коли ви оновили до нової версії веб-браузера, всі ваші вибрані закладки зламалися! Пам'ятайте, що концептуально користувач зберігає посилання на ресурс, а не на версію представлення ресурсу.
Даррел Міллер

11
@Gili Для того, щоб задовольнити вимогу, щоб api REST був самоописовим, необхідно, щоб заголовок типу вмісту містив повний семантичний опис повідомлення. Іншими словами, ваш тип носія - це ваш договір про передачу даних. Якщо ви доставляєте application / xml або application / json, ви нічого не повідомляєте клієнту про те, що міститься в цьому XML / Json. Момент, коли клієнтська програма потрапляє під час вимкнення / Клієнт / Ім'я, ви створюєте з'єднання, яке базується на інформації, відсутній у повідомленні. Усунення позадіапазонного зв'язку є надзвичайно важливим для досягнення RESTfulness.
Даррел Міллер

6
@Gili Клієнт не повинен знати попередніх URL-адрес API, крім кореневої URL-адреси. Не слід прив'язувати формати представлення до конкретних URL-адрес. Що стосується вибору типів мультимедіа, вам дійсно потрібно вибрати конкретний формат, наприклад application / vnd.mycompany.myformat + xml або стандартизований, як XHtml, Atom, RDF тощо.
Даррел Міллер,

4
Чи має сенс ставити версію API окремим полем заголовка? Так: Прийміть: application / com.example.myapp + json; версія = 1.0
Ерік

21

Ах, я знову надягаю свою стару жалібну шапку.

З точки зору відпочинку, це зовсім не має значення. Не ковбаса.

Клієнт отримує URI, який він хоче дотримуватися, і розглядає його як непрозорий рядок. Поклавши в нього все, що завгодно, клієнт не знає такої речі, як ідентифікатор версії.

Клієнт знає, що він може обробляти тип медіа, і я порадив би дотримуватися порад Даррела. Також я особисто вважаю, що потреба змінити формат, що використовується в спокійній архітектурі 4 рази, повинна принести величезні знакові попереджувальні знаки про те, що ви робите щось серйозно не так, і повністю обминаючи необхідність проектувати свій тип медіа для стійкості до змін.

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

Я особисто голосував би за http: // localhost / 3f3405d5-5984-4683-bf26-aca186d21c04

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


Що робити, якщо представництво має суттєво змінитися і не буде сумісним назад?
Майк Пон

1
Розробляючи тип медіа розширеним способом, наприклад, використовуючи простори імен та розширюваний xsd або існуючий формат xke ike atom, це слід запобігти. Якщо вам справді потрібно, інший тип медіа - це шлях.
SerialSeb

1
Мені подобається ця цілком коректна відповідь, але я думаю, що запропонований URI - це скоріше для демонстрації сенсу, ніж для реального сценарію, в якому ви хочете "зламати" URI.
Дейв Ван ден Ейнде

10

НЕ слід вводити версію в URL-адресу, ви повинні розмістити її в заголовку Прийняти запит - дивіться мою публікацію в цій темі:

Кращі практики для версії API?

Якщо ви почнете вставляти версії в URL-адресу, ви отримаєте такі дурні URL-адреси, як ця: http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

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


11
Вибачте, але я не думаю, що ви закінчуєтесь такими дурними URL-адресами, як ця. Ви прив’язуєте номери версій до певного ресурсу або (що ще гірше) до певного представлення. Це було б нерозумно, ІМО. Швидше за все, ви версуєте API, тому в URI ніколи не було б більше однієї версії.
crazy4jesus


3

Існує 4 різних підходи до версії API:

  • Додавання версії до шляху URI:

    http://example.com/api/v1/foo
    
    http://example.com/api/v2/foo
    

    Коли у вас є порушення зміни, ви повинні збільшити версію на зразок: v1, v2, v3 ...

    Ви можете реалізувати контролер у своєму коді так:

    @RestController
    public class FooVersioningController {
    
    @GetMapping("v1/foo")
    public FooV1 fooV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping("v2/foo")
    public FooV2 fooV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Запросити версію параметра:

    http://example.com/api/v2/foo/param?version=1
    http://example.com/api/v2/foo/param?version=2
    

    Параметр версії може бути необов’язковим або необхідним, залежно від того, як ви хочете використовувати API.

    Реалізація може бути подібною до цієї:

    @GetMapping(value = "/foo/param", params = "version=1")
    public FooV1 paramV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping(value = "/foo/param", params = "version=2")
    public FooV2 paramV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Проходження користувальницького заголовка:

    http://localhost:8080/foo/produces
    

    З заголовком:

    headers[Accept=application/vnd.company.app-v1+json]
    

    або:

    headers[Accept=application/vnd.company.app-v2+json]
    

    Найбільша перевага цієї схеми - це здебільшого семантика: ви не захаращуєте URI нічим спільним з версіями.

    Можлива реалізація:

    @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v1+json")
    public FooV1 producesV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v2+json")
    public FooV2 producesV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Зміна імен хостів або використання шлюзів API:

    По суті, ви переміщуєте API з одного імені хоста на інший. Ви навіть можете просто назвати цю будівлю новим API до тих же ресурсів.

    Також це можна зробити за допомогою шлюзів API.


2

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

На жаль, це рішення працює лише для авторизованих API. Однак це не захищає версії від URI.


2

Я хотів створити API-версії, і ця стаття була дуже корисною:

http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http

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


1

Я б включив версію як необов'язкове значення в кінці URI. Це може бути суфікс типу / V4 або параметр запиту, як ви описали. Ви можете навіть перенаправити / V4 на параметр запиту, щоб ви підтримували обидва варіанти.


1

Якщо ви використовуєте URI для версій, то номер версії повинен бути в URI кореня API, тому кожен ідентифікатор ресурсу може включати його.

Технічно API REST не розбивається на зміни URL-адреси (результат рівномірного обмеження інтерфейсу). Він порушується лише тоді, коли відповідна семантика (наприклад, специфічний для RDF vocab) зміна невідповідним чином (рідко). Наразі багато ppl не використовують посилання для навігації (обмеження HATEOAS) та vocabs, щоб анотувати свої REST-відповіді (обмеження на само описові повідомлення), тому їх клієнти перериваються.

Користувацькі типи MIME та версії MIME-типів не допомагають, оскільки розміщення відповідних метаданих та структури представлення у короткі рядки не працює. Ofc. метадані та структура часто змінюватимуться, і тому номер версії теж ...

Отже, щоб відповісти на ваше запитання найкращим способом анотувати ваші запити та відповіді за допомогою vocabs ( Hydra , пов’язані дані ) та забути версію або використовувати її лише невідповідними змінами vocab (наприклад, якщо ви хочете замінити vocab на інший).


0

Я голосую за те, щоб зробити це в mime type, але не в URL. Але причина не така, як у інших хлопців.

Я думаю, що URL-адреса повинна бути унікальною (крім цих переспрямувань) для пошуку унікального ресурсу. Так що , якщо ви приймаєте /v2.0в URL , чому це не так /ver2.0або /v2/або /v2.0.0? Або навіть -alphaі -beta? (тоді це повністю стає поняттям semver )

Отже, версія типу mime є більш прийнятною, ніж URL.

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