HATEOAS约束
HATEOAS(Hypermedia as the engine of application state)是 REST 架构风格中最复杂的约束,也是构建成熟 REST 服务的核心。它的重要性在于打破了客户端和服务器之间严格的契约,使得客户端可以更加智能和自适应,而 REST 服务本身的演化和更新也变得更加容易。
Richardson 提出的 REST 成熟度模型。该模型把 REST 服务按照成熟度划分成 4 个层次:
- 第一个层次(Level 0)的 Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
- 第二个层次(Level 1)的 Web 服务引入了资源的概念。每个资源有对应的标识符和表达。
- 第三个层次(Level 2)的 Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
- 第四个层次(Level 3)的 Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。
从上述 REST 成熟度模型中可以看到,使用 HATEOAS 的 REST 服务是成熟度最高的,也是推荐的做法。对于不使用 HATEOAS 的 REST 服务,客户端和服务器的实现之间是紧密耦合的。客户端需要根据服务器提供的相关文档来了解所暴露的资源和对应的操作。当服务器发生了变化时,如修改了资源的 URI,客户端也需要进行相应的修改。而使用 HATEOAS 的 REST 服务中,客户端可以通过服务器提供的资源的表达来智能地发现可以执行的操作。当服务器发生了变化时,客户端并不需要做出修改,因为资源的 URI 和其他信息都是动态发现的。
如果 Web 应用基于 Spring 框架开发,那么可以直接使用 Spring 框架的子项目 HATEOAS 来开发满足 HATEOAS 约束的 Web 服务。
基本配置:满足 HATEOAS 约束的 REST 服务最大的特点在于服务器提供给客户端的表达中包含了动态的链接信息,客户端通过这些链接来发现可以触发状态转换的动作。Spring HATEOAS 的主要功能在于提供了简单的机制来创建这些链接,并与 Spring MVC 框架有很好的集成。对于已有的 Spring MVC 应用,只需要一些简单的改动就可以满足 HATEOAS 约束。
资源:REST 架构中的核心概念之一是资源。服务器提供的是资源的表达,通常使用 JSON 或 XML 格式。在一般的 Web 应用中,服务器端代码会对所使用的资源建模,提供相应的模型层 Java 类,这些模型层 Java 类通常包含 JPA 相关的注解来完成持久化。在客户端请求时,服务器端代码通过 Jackson 或 JAXB 把模型对象转换成 JSON 或 XML 格式。在创建资源类时,可以继承自 Spring HATEOAS 提供的 org.springframework.hateoas.Resource 类,Resource 类提供了简单的方式来创建链接。ListResource 类继承自 Resource 类并对 List 类的对象进行了封装,添加了两个链接。
链接:HATEOAS 的核心是链接。链接的存在使得客户端可以动态发现其所能执行的动作。在上一节中介绍过链接由 rel 和 href 两个属性组成。其中属性 rel 表明了该链接所代表的关系含义。应用可以根据需要为链接选择最适合的 rel 属性值。由于每个应用的情况并不相同,对于应用相关的 rel 属性值并没有统一的规范。不过对于很多常见的链接关系,IANA 定义了规范的 rel 属性值。
超媒体控制与 HAL:在添加了链接之后,服务器端提供的表达可以帮助客户端更好的发现服务器端所支持的动作。在具体的表达中,应用虽然可以根据需要选择最适合的格式,但是在表达的基本结构上应该遵循一定的规范,这样可以保证最大程度的适用性。这个基本结构主要是整体的组织方式和链接的格式。HAL(Hypertxt Application Language)是一个被广泛采用的超文本表达的规范。应用可以考虑遵循该规范,Spring HATEOAS 提供了对 HAL 的支持。HAL 规范围绕资源和链接这两个简单的概念展开。资源的表达中包含链接、嵌套的资源和状态。资源的状态是该资源本身所包含的数据。链接则包含其指向的目标(URI)、所表示的关系和其他可选的相关属性。对应到 JSON 格式中,资源的链接包含在_links 属性对应的哈希对象中。该_links 哈希对象中的键(key)是链接的关系,而值(value)则是另外一个包含了 href 等其他链接属性的对象或对象数组。当前资源中所包含的嵌套资源由_embeded 属性来表示,其值是一个包含了其他资源的哈希对象。
目前 Spring HATEOAS 仅支持 HAL 一种超媒体表达格式,只需要在应用的配置类上添加“@EnableHypermediaSupport(type= {HypermediaType.HAL})”注解就可以启用该超媒体支持。在启用了超媒体支持之后,服务器端输出的表达格式会遵循 HAL 规范。另外,启用超媒体支持会默认启用“@EnableEntityLinks”。在启用超媒体支持之后,应用需要进行相关的定制使得生成的 HAL 表达更加友好。
首先是内嵌资源在_embedded 对应的哈希对象中的属性值,该属性值是由 org.springframework.hateoas.RelProvider 接口的实现来提供的。对于应用来说,只需要在内嵌资源对应的模型类中添加 org.springframework.hateoas.core.Relation 注解即可。