客户端使用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的功能以及服务器与客户端的分离非常有用。

但是,要点是,当我们构建客户端(例如带有Javascript的SPA或Android应用程序或许多其他东西)时,我看不到HATEOAS如何继续发挥作用。我的意思是:当我用javascript编码SPA时,我必须知道可以在API中完成什么才能编写代码。

因此,我需要知道资源,所支持的方法,它们期望接收什么以及它们返回什么,以便将ajax调用写入服务器,甚至还可以构建UI。在构建UI时,我必须知道请求帐户后,可以将其存入其中,否则我将无法在UI上提供此选项。另外,我将需要知道URI以进行存款以构建ajax调用。

我的意思是,当我们向API发出请求时,链接确实可以使我们更好地发现和使用API​​,但是当我们构建客户端时,我们正在构建的应用程序不会简单地查看链接,然后自己渲染正确的UI并进行正确的Ajax调用。

那么,HATEOAS对客户来说有多重要?无论如何,我们为什么还要打扰HATEOAS?


1
您是对的,但这不是重点。HATEOAS使您不必为客户端页面上的链接构造URI。
James McLeod 2015年

Answers:


24

我们正在构建的应用程序不会简单地查看链接,然后自己呈现正确的UI并进行正确的ajax调用

实际上,这正是 HATEOAS 提供的UI。没有什么是可能的,但是它是可能的。如问题所述,像HAL这样的形式化HATEOAS 提供了表明可能的链接。但是何时显示这些链接取决于应用程序的状态。因此,该链接可以改变的(已执行了基于动作)随着时间的推移资源。

这使我们能够构建一个包含所有可能状态的UI ,而不必担心这些状态何时变为活动状态。例如,的存在rel="deposit"可以直接告诉UI何时可以呈现make deposit表单。然后,它允许用户输入一个值并使用链接提交。


2
因此,在构建UI时,我们仍然需要知道API提供的所有内容,然后查看这些链接,我们是否能够知道服务器上信息的状态?因此,例如,UI知道可以存入,提取,转移或关闭(知道可能的不良情况),然后检查返回的内容以查看状态?
user1620696 2015年

1
是的,可以。同样,这取决于您要采用的动态程度。正如其他人提到的那样,更改服务器上的链接(而不破坏客户端)的能力是另一个优势。一旦您的API都使用了iPhone,Android,Windows Phone,Mobile Web和Web客户端,这就变得非常有趣(更不用说您的API是否发布给其他人来构建客户端)。
戴文·崔顿

@ user1620696无论如何,如果客户端和服务器都低估了内容类型,那么您应该都知道所有这些内容。内容类型比xml或Json愚蠢得多。您应该拥有某种让客户理解如何使用的“银行存款”内容类型
Cormac Mulhall 2015年

1
@Nik看看HAL,以了解如何在响应中提供链接的示例。
戴文·崔顿

1
是的,您仍然需要向后兼容。这可以通过在URL中包含版本标头或版本来解决。但是,我要说的是您理解正确。
戴文·崔顿

3

据我目前的了解,HATEOAS基本上是与每个响应链接一起发送,并带有有关下一步操作的信息

HATEOAS不仅仅是链接。它是“超级媒体”作为应用程序状态的引擎。

您的描述中缺少的是内容类型,即客户端和服务器之间传递的超媒体的正式定义。

HTML是超媒体的一个示例,也是HATEOS工作原理的一个示例。HTML页面本身是允许客户端(即用户)在站点中移动的引擎。仅具有向用户呈现HTML的功能的浏览器,它可以向用户提供完全可导航的网站。它不只是将链接传递到其他页面,而且还以有意义的方式传递它们,从而为链接提供上下文,并以允许浏览器构造可导航站点的方式传递。

最重要的是,浏览器可以通过对网站本身的零了解来做到这一点。浏览器仅知道HTTP和HTML。基于这种简单的理解,它可以向用户显示《纽约时报》以进行浏览。

即使“用户”是另一个计算机程序,也是如此。超媒体本身应定义导航的上下文。


1
这是否意味着您必须构建与浏览器一样复杂(且容易出错)的客户端?灵活性通常伴随着复杂性而付出代价……
Andres F.

@AndresF。这并不意味着您必须应该这样做,它只是使您可以选择是否愿意或需要它来动态进行。
彼得斯,2015年

2
@nik当然。令我烦恼的是,您想像一下您有一项可通过宁静的api提供血统信息的服务。您具有一个内容类型,该内容类型定义“人”资源的格式,该资源具有关于它们的各种信息,还定义了什么样的关系,例如“兄弟”或“姐妹”或“母亲”等。因为这是超媒体,所以这些关系只是具有另一个Person资源的URI。一个使用HTTP动词并了解此“人”内容类型的相当简单的客户端可以浏览此API。假设您要查找特定人员的所有直接后代。
Cormac Mulhall

2
@nik该客户端只需了解它已访问的资源和HTTP谓词(GET,PUT,DELETE等)的内容类型,即可浏览此API来获取和更新资源。而且,更重要的是,任何了解内容类型的客户端都可以通过URI完全跳到另一台服务器,然后继续运行。他们不在乎与之交谈的服务器,他们只关心资源的内容类型,是否了解。
Cormac Mulhall

1
@Nik因此,在这种情况下,您的服务器可以理解原始内容类型(例如Person v1)和新内容类型(Person v2)。客户端仅了解Person v1。客户端通过HTTP中的Accept标头告诉服务器它理解什么内容类型。服务器使用内容协商确定是否将发送客户端支持的内容,在这种情况下,它将使用内容类型Person v1返回资源。现在,您可能只想停止支持此旧内容类型,并可以向客户端发送406错误。最好尝试并尽可能多地提供支持。
Cormac Mulhall

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的意义何在。
Ruslan Stelmachenko
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.