Який сенс HATEOAS на стороні клієнта?


35

Як я зараз розумію, HATEOAS - це все, що стосується надсилання разом із кожним посиланням відповіді з інформацією про те, що робити далі. В Інтернеті легко знайти один простий приклад: банківська система разом із ресурсом рахунку. Приклад показує цю відповідь після запиту GET на ресурс облікового запису

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">100.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
    <link rel="withdraw" href="/account/12345/withdraw" /> 
    <link rel="transfer" href="/account/12345/transfer" /> 
    <link rel="close" href="/account/12345/close" /> 
</account>

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

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">-25.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
</account>

Так що ми можемо лише здати на зберігання. Це все добре, якщо ми використовуємо Fiddler або робимо запити за допомогою браузера, ми можемо легко побачити, що можна зробити. Така інформація є корисною для того, щоб ми розкрили можливості API і сервер був від'єднаний від клієнта.

Суть, однак, полягає в тому, що коли ми створюємо клієнта, наприклад, SPA з Javascript або додатком для Android або багатьох інших речей, я не можу побачити, як HATEOAS продовжує бути актуальним. Я маю на увазі таке: коли я кодую SPA в javascript, я повинен знати, що можна зробити в API, щоб написати код.

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

Що я маю на увазі, коли ми робимо запити до API, посилання дійсно дозволяють нам виявити та використовувати API краще, але коли ми будуємо клієнт, додаток, який ми будуємо, не буде просто дивитись на посилання, а потім сам по собі видавати правильний інтерфейс користувача та здійснювати правильні дзвінки ajax.

Отже, наскільки HATEOAS важливий для клієнтів? Чому ми взагалі турбуємось з HATEOAS?


1
Ти маєш рацію, але це не в цьому. HATEOAS не дає вам створювати URI для посилань на сторінці клієнта.
Джеймс МакЛейд

Відповіді:


24

додаток, який ми будуємо, не буде просто дивитись на посилання, а потім самому надавати правильний інтерфейс та робити правильні дзвінки Ajax

Насправді, це саме те , що HATEOAS буде давати призначений для користувача інтерфейс. Не те, що можливо, але коли це можливо. Формальний HATEOAS на зразок HAL , як зазначено в питанні, дає посилання, які вказують, що можливо. Але коли з’являться ці посилання, залежить від стану програми. Отже, посилання можуть змінюватися на ресурсі з часом (на основі дій, які вже були виконані).

Це дозволяє нам створити інтерфейс користувача, який містить усі можливі стани, але не переймається тим, коли ці стани стають активними. Наприклад, наявність віконця rel="deposit"може безпосередньо повідомити користувальницький інтерфейс, коли буде вірно надати make depositформу. Що дозволяє користувачеві вводити значення та подавати, використовуючи посилання.


2
Отже, будуючи інтерфейс, ми все ще мусимо знати все, що пропонує API, а потім, переглядаючи ці посилання, ми можемо знати, у якому стані знаходиться інформація на сервері? Так, наприклад, користувальницький інтерфейс знає, що можна здати на зберігання, зняти, перенести або закрити (знає можливі релізи), а потім перевіряє, що повернулося, щоб побачити стан?
користувач1620696

1
Так, це могло б. Знову це залежить від того, наскільки динамічно ви хочете його прийняти. Як вже згадували інші, можливість змінити посилання на сервері (а не ламати клієнтів) - ще одна перевага. І це стає дуже цікавим, коли у вашому API є клієнти iPhone, Android, Windows Phone, Mobile Web та Web, які всі користуються ним (не кажучи вже про те, якщо ваш API публікується для інших клієнтів).
Давін Тріон

@ user1620696 Ви все-таки повинні знати все це як через клієнт, так і на сервер, не розуміючи тип вмісту, якщо це resoure. Тип вмісту набагато більше, ніж німий xml або Json. У вас має бути якийсь тип вмісту "банківського вкладу", з яким клієнт розуміє, як працювати
Cormac Mulhall

1
@Nik подивіться на HAL для прикладу того, як надаються посилання у відповіді.
Давін Тріон

1
так, у вас все ще виникають проблеми щодо сумісності. Це можна вирішити, включивши заголовок версії або версію в URL-адресу. Але, я б сказав, ви правильно розумієте.
Давін Тріон

3

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

HATEOAS - це набагато більше, ніж просто посилання. Це "гіпермедіа" як двигун стану додатків.

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

HTML - приклад гіпермедіа та приклад того, чому працює HATEOS. Сама сторінка HTML - це двигун, який дозволяє клієнту (тобто користувачеві) пересуватися через сайт. Веб-переглядач із лише можливістю надання HTML-презенту користувачеві повністю навігаційного веб-сайту. Це не просто те, що він передає посилання на інші сторінки, але він передає їх змістовно, що дає контекст посиланням і таким чином, що дозволяє браузеру створювати навігаційний сайт.

І найголовніше, що браузер може це зробити, використовуючи ZERO наперед розуміння самого веб-сайту. Браузер знає лише HTTP та HTML. Виходячи з цього простого розуміння, він може подарувати користувачеві New York Times користувачеві навігацію.

Це справедливо, навіть якщо "користувач" є іншою комп'ютерною програмою. Сам гіпермедіа повинен визначати контекст навігації.


1
Чи не означає це, що ви повинні створити клієнта настільки складний (і схильний до помилок), як браузер? Гнучкість часто буває складною як вартість ...
Андрес Ф.

@AndresF. це не означає, що ви повинні чи повинні робити це, він просто дає вам можливість робити це динамічно, якщо ви цього хочете чи потребуєте.
Петріс

2
@nik Звичайно. У верхній частині голови уявіть, що у вас є послуга, що надає інформацію про родину через спокійні api. У вас є тип вмісту, який визначає формат ресурсу "Особа", який містить різноманітну інформацію про них, а також визначає, як виглядають відносини, скажімо, "брат" або "сестра" або "мати" і т. Д. Тому що це гіпермедіа ці стосунки просто мати URI для іншого ресурсу Person. Досить простий клієнт, який використовує дієслова HTTP і розуміючи цей тип вмісту "Особи", може переходити через цей API. Скажіть, ви хочете знайти всіх прямих нащадків конкретної людини.
Кормак Малхолл

2
@nik Цей клієнт повинен просто зрозуміти тип вмісту ресурсу, до якого він отримував доступ, і HTTP-дієслова (GET, PUT, DELETE тощо), і ви можете переходити через цей API отримання та оновлення ресурсів. І, що ще важливіше, будь-який клієнт, який розуміє тип вмісту, може перейти через URI повністю на інший сервер і продовжити так, як був. Їм не байдуже, на якому сервері вони розмовляють, вони дбають лише про тип вмісту ресурсу, розуміють вони це чи ні.
Кормак Малхолл

1
@Nik Отже, у такій ситуації у вас є сервер, який розуміє вихідний тип вмісту (скажімо, Person v1) та новий тип вмісту (Person v2). Клієнт розуміє лише Person v1. Клієнт повідомляє серверу, які типи вмісту він розуміє через заголовок Accept у HTTP. Використовуючи узгодження контенту, сервер визначає, чи надсилатиме те, що підтримує клієнт, і в цьому випадку він поверне ресурс, використовуючи тип вмісту Person v1. Тепер ви можете просто перестати підтримувати цей старий тип вмісту і можете надіслати клієнту помилку 406. Краще спробувати та підтримати, наскільки це можливо.
Кормак Малхолл

2

Вам не потрібно будувати інтерфейс, що динамічно генерується. Хоча це може бути добре, це не потрібно. Якщо ви не можете побудувати динамічний інтерфейс, просто скористайтеся посиланнями, і ви закінчите. Недоліком є ​​те, що ви знову жорстко пов'язані з бекендом, і вийде з ладу, якщо щось зміниться.

Використовувати динамічний макет може бути досить простим btw:

links.forEach(function(link) {

  switch(link.rel) {

    case 'deposit':
      showDepositButton();
      break;

    case 'withdraw':
      loadWithdrawForm(link.href);
      showWithdrawButton();
      break;
  }

});

Це зберігає вас у вашому коді клієнта, як:

if (balance <= 0 && negativeBalanceAllowed === false) {
  showWithdrawButton();
}

Ви можете реалізувати дозволену негативну позицію (наприклад, позичивши гроші), не змінюючи клієнта.


Як дещо вагоміший приклад, банк може запропонувати змінні ліміти овердрафту на своїх рахунках, не повідомляючи клієнту, який ліміт є для кожного рахунку.
Барт ван Іґен Шенау

Правильно, ви можете зробити ліміт балансу настільки складним, наскільки ви хочете, і все одно не потрібно вносити зміни до клієнта. Якщо ви продовжите це з частинами REST, як-от тип вмісту, ви можете показати різні погляди. Наприклад, рахунок виглядає не так, як транзакція. Також цікавим є код на вимогу (хоча і не дуже реалізований). Це може бути використане, наприклад, для оцінювача запозичень. Він може надати інтерфейсу просту функцію калькулятора, тому клієнту потрібно лише реалізувати вхідні дані для розрахунку. Він буде в курсі останніх версій.
Люк Франкен

2
Але зазвичай клієнт повинен знати, ЧОМУ він не може зняти, тому нам все одно потрібно надіслати ENUM або String в окремому полі для клієнта reason. І якщо нам це ще потрібно, то чому б просто не надіслати йому ще одне булеве поле canWithdrawзамість посилання на дію? Ще одна перевага - можливість змінити URL-адресу дії, не торкаючись клієнта. Але .. яка причина змінити URL-адресу? У більшості випадків це також деяка зміна семантичних чи параметрів, форми запиту / відповіді тощо. Тому нам все одно потрібно змінити клієнта. Отже, я все ще не розумію - який сенс HATEOAS.
Руслан Стельмаченко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.