Какой смысл с 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?

user1620696
источник
1
Ты прав, но дело не в этом. HATEOAS не позволяет вам создавать URI для ссылок на странице на клиенте.
Джеймс Маклеод

Ответы:

24

приложение, которое мы создаем, не просто просматривает ссылки, а затем само отображает правильный пользовательский интерфейс и делает правильные вызовы ajax

На самом деле, это именно то , что HATEOAS будет давать пользовательский интерфейс. Не то, что возможно, а когда это возможно. Формальные HATEOAS, такие как HAL , как говорится в вопросе, дают ссылки, которые указывают, что возможно. Но когда эти ссылки появляются, зависит от состояния приложения. Таким образом, ссылки могут изменяться на ресурсе с течением времени (в зависимости от уже выполненных действий).

Это позволяет нам создавать пользовательский интерфейс, содержащий все возможные состояния, но не заботиться о том, когда эти состояния станут активными. Например, наличие rel="deposit"может напрямую сообщать пользовательскому интерфейсу, когда можно выполнить визуализацию make depositформы. Который затем позволяет пользователю ввести значение и отправить, используя ссылку.

Дэвин Трайон
источник
2
Таким образом, при создании пользовательского интерфейса нам все еще нужно знать все, что предлагает API, а затем, глядя на эти ссылки, мы можем узнать, в каком состоянии находится информация на сервере? Так, например, пользовательский интерфейс знает, что можно вносить, снимать, переводить или закрывать (знает возможные значения), а затем проверяет, что вернулось, чтобы увидеть состояние?
user1620696
1
Да, это возможно. Опять же, это зависит от того, насколько динамично вы хотите это принять. Как уже упоминалось, возможность изменять ссылки на сервере (а не прерывать работу клиентов) - еще одно преимущество. И это становится очень интересным, когда у вашего API есть iPhone, Android, Windows Phone, мобильный Интернет и веб-клиенты, которые все используют его (не говоря уже о том, что ваш API опубликован для других, на которых можно строить клиентов).
Давин Трайон,
@ user1620696 Вы все равно должны знать все это как через клиент, так и на сервере, подчеркивая тип контента при поиске. Тип контента намного больше, чем тупой XML или JSON. У вас должен быть некоторый тип контента «банковский депозит», с которым клиент понимает, как работать
Cormac Mulhall
1
@Nik посмотрите на HAL для примера того, как ссылки предоставлены в ответе.
Дэвин Трайон
1
да, у вас все еще есть проблемы обратной совместимости. Это может быть решено включением заголовка версии или версии в URL. Но я бы сказал, что вы все правильно поняли.
Дэвин Трайон
3

Как я сейчас понимаю, HATEOAS - это в основном отправка вместе с каждым ответом ссылок с информацией о том, что делать дальше.

HATEOAS - это намного больше, чем просто ссылки. Это «гипермедиа» как двигатель состояния приложения.

Что упущено в вашем описании, так это тип контента, формальное определение гиперссылки, передаваемой между клиентом и сервером.

HTML является примером гипермедиа и примером того, почему HATEOS работает. HTML-страница сама по себе является механизмом, который позволяет клиенту (т.е. пользователю) перемещаться по сайту. Браузер с возможностью отображения HTML предоставляет пользователю полностью ориентируемый веб-сайт. Это не просто то, что он передает ссылки на другие страницы, но он передает их осмысленным образом, который дает контекст ссылкам и таким образом, который позволяет браузеру создавать навигационный сайт.

И самое главное, браузер может сделать это с нулевым пониманием самого сайта. Браузер знает только HTTP и HTML. Основываясь на этом простом понимании, он может представить пользователю New York Times для навигации.

Это верно, даже если «пользователь» - это другая компьютерная программа. Гипермедиа должно определять контекст навигации.

Кормак Мулхолл
источник
1
Не означает ли это, что вы должны создать клиент столь же сложный (и подверженный ошибкам), как браузер? Гибкость часто приходит со сложностью как стоимость ...
Андрес Ф.
@AndresF. это не означает, что вы должны или должны делать это, это просто дает вам возможность сделать это динамически, если вы хотите или нуждаетесь в этом.
Петерис
2
@ Ник Конечно. Вдобавок ко всему, представьте, что у вас есть сервис, предоставляющий информацию о родословной через успокоительный 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

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

Использование динамического макета может быть довольно простым:

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.
Руслан Стельмаченко