RESTful API 运行时发现 / HATEOAS 客户端设计

80
我参与的一家SaaS初创公司正在构建一个RESTful Web API以及几个在不同平台上使用该API的客户端应用。我认为我已经搞清楚了API,但现在我转向客户端。我读到REST相关的内容时,发现REST的一个关键部分是“发现”,但似乎有很多关于发现到底意味着什么的争论:
1.开发者发现:开发人员在客户端中硬编码大量API细节,例如资源URI、查询参数、支持的HTTP方法和其他通过浏览文档和尝试API响应而发现的细节。这种类型的发现需要很酷的链接和API版本问题,并导致客户端代码与API之间出现硬耦合。看起来并没有比使用良好记录的RPC集合更好。
2.运行时发现-客户端应用程序本身能够在很少或没有带外信息的情况下找到它所需要的一切(可能只需要知道API处理的媒体类型)。链接可以热更新。但是为了使API非常高效,似乎需要很多链接模板来处理查询参数,这会让带外信息再次渗入。可能还存在我还没有想到的其他困难,因为我还没有到开发的那个阶段。但我确实喜欢松散耦合的想法。
运行时发现似乎是REST的终极目标,但我看到很少关于如何实现这样的客户端的讨论。几乎所有我找到的REST来源都似乎假定开发人员发现。有了解运行时发现资源的人吗?最佳实践?具有真实代码的示例或库?我在PHP(Zend Framework)上为一个客户端工作。对于另一个客户端,我使用Objective-C(iOS)。

考虑到开发者社区现有的工具和知识,运行时发现是否是一个现实目标?我可以编写客户端以不透明的方式处理所有URI,但如何以最有效的方式进行处理是一个问题,特别是在低带宽连接情况下。无论如何,URI只是方程式的一部分。在运行时上下文中,链接模板怎么办?除了进行大量的OPTIONS请求之外,如何传达支持哪些方法的信息呢?


2
关于你的OPTIONS参考,稍微提一下。你可以使用“允许”头来在OPTIONS请求之外通信允许的资源操作。Roy Fielding甚至认为这个头部是超文本的一种形式 - 参见这里 - paulkmoore
这是一个很好的问题,关键问题在于给定适用方法列表后,客户端是否能够为常规CRUD操作形成URL,或者是否将其称为“out-of-band”?例如,如果我们也为CRUD操作提供链接,如何在JSON中进行“表单”?也许如果您使用特定于应用程序的媒体类型,则不需要执行“表单”,但是发现媒体类型(即JSON模式)的标准方法是什么?发现模式的过程是否被认为对客户端来说不是“out-of-band”? - redzedi
xhtml看起来非常好,流畅自然,但如果你必须使用JSON,我想现在它可能有些无定形。 - redzedi
6个回答

19

这绝对是一道难题。在谷歌,我们实现了我们的 Discovery 服务,所有新的 API 都建立在此之上。TL;DR 版本是我们生成了一个类似于 JSON Schema 的规范,我们的客户端可以解析它 —— 其中许多是动态的。

结果就是开发者更容易升级 SDK,并且更容易/更好地进行维护。

虽然这不是完美的解决方案,但我们的许多开发人员似乎都喜欢它。

详细信息请参见 链接(一定要观看视频)。


有没有一种标准来为我们自己的API实现这样的发现服务? - Çağatay Gürtürk

12

有趣。你所描述的基本上是HATEOAS原则。你问什么是HATEOAS?看这个:http://en.wikipedia.org/wiki/HATEOAS

通俗易懂地说,HATEOAS意味着链接跟随。这种方法将客户端与特定的URL分离,使您能够灵活更改API而不会影响到其他人。


6
在您称呼一个API为“RESTful”之前,应满足的要求之一是必须能够在该API之上编写通用客户端应用程序。使用通用客户端,用户应能够访问所有API功能。通用客户端是一种客户端应用程序,不假设任何资源具有除媒体类型定义的结构之外的特定结构。例如,Web浏览器是一个通用客户端,知道如何解释HTML,包括HTML表单等。
现在,假设我们有一个HTTP / JSON API用于Web商店,并且我们想要构建一个HTML / CSS / JavaScript客户端,以给我们的客户提供出色的用户体验。让该客户端成为通用客户端应用程序是否是一个现实选项?不是。我们希望为每个特定的数据元素和每个特定的应用程序状态提供特定的外观和感觉。我们不想在API中包含有关这些特定呈现方式的所有知识,相反,客户端应定义外观和感觉,而API只应承载数据。这意味着客户端将特定资源元素硬编码到特定布局和用户交互中。
这是HATEOAS的终结,因此也是REST的终结吗?是和否。

是的,因为如果我们在客户端中硬编码关于API的知识,我们会失去HATEOAS的好处:服务器端的更改可能会破坏客户端。

不是,有两个原因:

  1. “RESTful”是API的属性,而不是客户端的属性。只要理论上可以构建一个提供API所有功能的通用客户端,API就可以被称为RESTful。客户端不遵守规则并不是API的问题。通用客户端用户体验差不是问题。如果我们实际上没有这个通用客户端,那么知道有可能有通用客户端是重要的吗?这带我到第二个原因:
  2. RESTful API为客户端提供了选择多么通用的选项,即他们想要多么弹性地适应服务器端变化。需要提供良好用户体验的客户端仍然可以适应URI更改,更改默认值等。进行批处理作业且无需用户交互的客户端可能对其他类型的更改具有弹性。

如果您对实际示例感兴趣,请查看我的JAREST论文。最后一部分是关于HATEOAS的。您将会发现,在使用JAREST时,即使高度交互和视觉上有吸引力的客户端也可以相当抗拒服务器端的更改,尽管不是100%。


6

1

我认为HATEOAS的重要点不在于它是客户端的某种圣杯,而在于它将客户端与URI更改隔离开来——假定您正在使用已知(或开发人员发现的自定义)链接关系,这将允许系统知道哪个对象的链接是可编辑表单。重要的是使用超媒体感知的媒体类型(例如HTML、XHTML等)。


0
你的写法如下:

为了使 API 更有效,似乎需要使用大量查询参数的链接模板,这会导致外带信息再次出现。

如果前一个请求中提供了该链接模板,则没有外带信息。例如,HTML 搜索表单使用链接模板 (/search?q=%@) 生成 URL (/search?q=hateoas),但客户端(Web 浏览器)只知道如何使用 HTML 表单和 GET,不知道其他任何信息。


确实没有带外信息 - 客户端负责使用提供的资源/实例数据扩展URI模板(并且应该知道如何执行此操作)- http://json-schema.org/latest/json-schema-hypermedia.html#anchor18 - fusi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接