HATEOAS客户端设计

时间:2012-02-24 18:04:14

标签: rest api-design hateoas

我在这里看了很多关于SO的讨论,看了Jon Moore's presentation(解释了很多,顺便说一句),并阅读了Roy Fielding关于HATEOAS的博客文章但我仍然感到有点陷入黑暗中客户设计。

API问题

现在,我只是返回带有表单/锚点和定义列表的xhtml来表示资源。以下代码段详细说明了我如何布置表单/锚点/列表。

# anchors
<li class='docs_url/#resourcename'>
  <a rel='self' href='resource location'></a>
</li>

# forms
<form action='action_url' method='whatever_method' class='???'></form>

# lists
<dl class='docs_url/#resourcename'>
    <dt>property</dt>
    <dd>value</dd>
</dl>

我的问题主要是表格。在Jon的演讲中,他记录了诸如(add_location_form)等表单类型以及它们所需的输入。我没有很多资源,但我正在考虑抽象表单类型(添加,删除,更新等),并在文档中注意,(添加,更新)您必须发送目标资源的有效表示并删除,您必须发送标识符。

问题1: 有了HATEOAS的概念,我们真的不应该让客户“发现”表单(通过对它们进行分类添加,删除,更新等) )并发回我们给他们的所有数据?我在这里的真正问题(不是一个讨论)是否遵循良好做法?

客户问题

遵循HATEOAS,我们对可发现的资源采取的行动如何影响客户端代码(api的消费者)及其ui。听起来很棒,按照这些原则,UI应该只显示可用的操作但是如何实现?

我目前的方法是将响应解析为xml和usin xpath,以查找客户端开发时已知的操作(记录的表单类,即添加,删除,更新),并显示ui控件是否可用

问题2: 我的发现方式错了吗?或者就客户而言(知道表格类别)这太过神奇了吗?这不会假设客户端知道哪些操作可用于每个资源(这可能很好,因为它是创建客户端的一种原因,对吗?)并且应该记录操作(表单类)到资源的映射,或只是记录表单类,并允许客户端(和客户端开发人员)研究和发现它们?

我知道我到处都是这个,但任何见解都非常感激。我会回答一个回复,回答这两个问题中的任何一个。谢谢!

1 个答案:

答案 0 :(得分:6)

不,你非常喜欢。

浏览器只是渲染HTML有效负载,并依赖于人类实际解释,找到意义,并可能适当地填充表单。

到目前为止,机器客户往往在#34;解释&#34;部分。因此,开发人员必须提前做出决策,并引导机器客户端处理难以理解的细节。

理想情况下,&#34; smart&#34; HATEOS客户端会有一些事实,并了解上下文,以便更好地将这些事实映射到服务的要求。

因为那是我们的所作所为,对吧?我们看到一个表格&#34;哦,他们想要姓名,地址,信用卡号码&#34;。我们不仅知道&#34;名称&#34;,&#34;地址&#34;和&#34;信用卡&#34;数字意思是,我们也可以知道他们的意思是我的名字,或信用卡上的人的姓名,或者被运送到的人的姓名。

机器在&#34; intuit&#34;中很容易失败。部分也是如此。因此,作为一名开发人员,您可以根据您认为可能需要的逻辑来编写代码,以确定正确的事实及其放置方式。

但是,回到理想的客户,它会看到每个表格,&#34;知道&#34;这些字段需要什么,查阅其内部的&#34;事实&#34;列表,然后正确填充请求的有效负载,最后发出请求。

你可以看到,这样做的一个微不足道的,显而易见的方法是简单地将参数名称映射到内部数据。当参数名称为&#34; name&#34;时,您可能会将其硬编码为:firstName +&#34; &#34; + lastName。或者您可以将实际的rel视为&#34; know&#34;他们正在谈论运输,并使用:shipTo.firstName +&#34; &#34; + shipTo.lastName。

随着时间的推移,理想情况下你可以构建一个映射集合,这样如果突然有效负载引入了一个新字段,而它恰好是你已经知道的字段,那么你也可以填写它#34 ;自动&#34;没有改变客户。

但简单的事实是,尽管可以做到这一点,但它几乎没有完成。语义通常是含糊不清的,你必须用新的直觉来编码&#34;无论如何,每次都为每个新的有效负载,所以你也可以直接编码到有效载荷并完成它。

但关键的是,特别是关于HATEOS,关键是你不要强迫&#34;您的数据到服务器。服务器会告诉您它想要什么,特别是如果他们给您提供表格。

所以思考过程不是&#34;哦,如果我想要一个发货发票,我看到,现在,他们想要名称,地址和订单号,他们想要它的网址编码,他们希望它发送到http://example.com/shipping_invoice。所以我总是发送:姓名+&#34;&amp;&#34; +地址+&#34;&amp;&#34; + orderNumber每次http://example.com/shipping_invoice。简单!&#34 ;.

而你想要做的是&#34;我看到他们想要一个名字,地址和订单号。所以我要做的就是每个请求,我会阅读他们的表格。我会每次检查他们想要的字段。如果他们想要名字,我会给他们起名字。如果他们想要地址,我会给他们地址。如果他们想要订单号,我会给他们订单号。如果他们有任何PRE-POPULATED字段(甚至&#34;隐藏&#34;字段),我也会将它们发回去,我会以他们要求的编码发送它,假设我支持它,到URL我从FORM标签的操作字段中获取。&#34;。

您可以在前一种情况下看到,您每次都希望他们想要有效负载。就像你在硬编码URL一样。然而,对于第二个,也许他们认为名称和地址是多余的,所以他们不再要求它。也许他们为你可能不支持的新功能添加了一些不错的默认值。也许他们将编码改为多部分?或者更改了端点URL。谁知道呢。

您只能在编写客户端代码时发送您所知道的内容,对吧?如果他们改变了事情,那么你只能做你能做的事情。如果他们添加字段,希望他们添加不需要的字段。但是,如果他们打破了界面,嘿,他们打破了界面,你就会记录错误。你可以做的不多。

但是你利用HATEOS部分的次数越多,它们就越多,你可以更灵活:填写表格,正确重定向,注意编码和媒体类型,你的客户就越灵活变。

最后,大多数人根本不会在他们的客户中做到这一点。他们硬编码,因为它很简单,并且他们认为后端没有足够快速地改变,或者如果发生这种改变,任何停机都是可接受的,直到他们纠正客户端为止。更典型的是,特别是对于内部系统,您只需从开发人员那里收到一封电子邮件,他们正在更改XYZ API,并且它将于3月1日上线。请在集成测试期间更新您的客户并与发布团队协调。 kthx&#34;

这就是现实。这并不意味着你不应该这样做,或者你不应该让你的服务器对更聪明的客户更友好。记住一个糟糕的客户端,假设一切都不会使一个好的基于REST的系统失效。这些系统适用于糟糕的客户端。 wget ftw,嗯?