10

一位开发人员(现已离开)使我确信,发展 RESTful Web 服务的正确方法是为您的服务创建自定义媒体类型。

例如 application/vnd.acme.payroll.v1+json

这样,您可以告诉您的客户端指定要使用的编码,而无需更改 URI。

这种技术好不好?通常服务会将版本嵌入到 url 中:

例如/acme/1.0/payroll/

我在强制客户使用这个方案时遇到了很多困难,特别是因为 DELETE 似乎没有强制使用媒体类型

4

2 回答 2

19

您可以在 RESTful 服务中使用一些主要的信号机制:

  • 媒体类型
  • rel您链接到的资源的。
  • 自定义标头,例如Accept-Version/ Api-Version

它们中的每一个都有不同的用途,我将概述我们在设计 API 时理解它们的方式。


媒体类型

为了表明对给定资源可以进行哪些操作,以及这些操作的语义是什么,许多人使用自定义媒体类型。在我看来,这并不完全正确,而 arel更准确。

自定义媒体类型应该告诉您数据的类型,例如其格式或某些信息的体现或嵌入方式。拥有自定义媒体类型意味着您的 API 的使用者与该特定表示紧密耦合。然而,使用更通用的东西,比如application/json“这只是 JSON 数据”。

通常仅 JSON 不足以用于 RESTful 服务,因为它没有内置链接或资源嵌入功能。这就是像HAL ( application/hal+json) 这样的东西的用武之地。它是 JSON 的一种特殊化,仍然是一种通用格式,而不是特定于应用程序的格式。但它足以覆盖 JSON 之上的链接和嵌入语义,这是连贯地表达 RESTful API 所必需的。

链接关系类型(rels)

这将我们带到了rels。对我来说,自定义 rel 是一种完美的方式来表明正在处理或链接到哪种类型的资源。例如,rel用户资源的自定义可能是http://rel.myapi.com/user,它有两个目的:

  • 您的 API 的客户端必须提前知道此密钥,因为它是特定于 API 的知识。例如,如果它在您的初始资源上可用并且您正在使用 HAL 链接到用户资源,则客户端可能会通过initialResource._links["http://rel.myapi.com/user"].href.
  • 编写API 客户端的开发人员可以在他们的 Web 浏览器中访问该 URI,并了解该资源在您的 API 中代表什么,包括哪些方法适用以及它们做什么。这是一种非常方便的方式来传达我提到的 API 特定知识。有关这方面的示例,请参阅http://rel.nkstdy.co

如果您将rels 与标准或半标准媒体类型(如)结合使用application/hal+json,您将获得遵循其媒体类型指定的统一格式的资源,以及由其rels 定义的 API 特定语义。这几乎可以让你到达那里。

自定义标题

剩下的问题是版本控制。您如何允许客户端协商资源的不同版本,同时又不使旧 URI 失效?

我们的解决方案受Restify Node.js 框架的启发,是两个自定义标头:Accept-Version来自客户端,与服务器非常匹配X-Api-Version(或Api-Version在即将发布的 Restify 2.0 版本中,根据新的RFC 6648)。如果它们不匹配,400 Bad Request则结果为 a。

我承认自定义媒体类型在这里是一个相当流行的解决方案。在我看来,鉴于上述考虑,它们在概念上不太合适,但如果你选择它们作为你的版本控制机制,你就不会做一些奇怪的事情。GET正如您所注意到的,当与其他方法一起使用时,它会出现一些语义问题。

要记住的一件事是,在真正的 RESTful 系统中,版本控制不应该是这样的问题。它只在一种非常特殊的情况下才重要:当您的资源表示以向后不兼容的方式发生变化时,但您仍然希望保持相同rel的 s. 因此,如果http://rel.myapi.com/friend资源突然失去了它的username领域并获得了一个id领域,那将是合格的。但是如果它突然获得了一个nickname字段,那并不是向后不兼容的,所以不需要版本控制。如果“朋友”的概念在你的 API 中完全被“连接”的概念取代,这实际上并不是向后不兼容的,因为 API 使用者将不再http://rel.myapi.com/friend在 API 中的任何地方找到链接供他们遵循.

于 2012-07-17T03:59:41.967 回答
3

是的,这是一个不错的选择。正如您正确指出的那样,它阐明了您将用于有效负载的编码,并让双方在不更改 URI 的情况下协商不同版本的编码。

是的,客户端不需要连同实体主体一起发送 DELETE。我相信它会被兼容的 HTTP 服务器简单地忽略,因为在这种情况下没有传输有效负载数据。客户端为 URI 发出 DELETE,服务器返回一个响应代码,指示它是否成功。又好又简单!如果服务器希望在 DELETE 之后返回一些数据,那么它可以自由地这样做,并且应该在它返回时指定响应的媒体类型。

于 2012-07-17T02:25:29.187 回答