API版本控制的最佳实践?

时间:2008-12-23 15:32:42

标签: rest versioning

Web服务REST API版本控制是否有任何已知的方法或最佳实践?

我注意到AWS does versioning by the URL of the endpoint。这是唯一的方法还是有其他方法来实现同一目标?如果有多种方式,每种方式的优点是什么?

7 个答案:

答案 0 :(得分:684)

答案 1 :(得分:273)

网址不应包含版本。该版本与您请求的资源的“想法”无关。您应该尝试将URL视为您想要的概念的路径 - 而不是您希望项目返回的方式。版本规定了对象的表示,而不是对象的概念。正如其他海报所说,你应该在请求标题中指定格式(包括版本)。

如果查看具有版本的URL的完整HTTP请求,它看起来像这样:

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

标题包含包含您要求的表示的行(“Accept:application / xml”)。那是版本应该去的地方。每个人似乎都掩盖了这样一个事实,即你可能想要不同格式的相同的东西,并且客户应该能够询问它想要什么。在上面的示例中,客户端要求资源的 ANY XML表示 - 实际上并不是它想要的真实表示。理论上,服务器可以返回与请求完全无关的内容,只要它是XML,并且必须进行解析才能意识到它是错误的。

更好的方法是:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

此外,假设客户认为XML太冗长,现在他们想要JSON。在其他示例中,您必须为同一客户提供新的URL,因此最终会得到:

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(或类似的东西)。实际上,每个HTTP请求都包含您要查找的格式:

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

使用此方法,您可以更自由地设计,并且实际上遵循REST的原始概念。您可以在不中断客户端的情况下更改版本,也可以在API更改时逐步更改客户端。如果您选择停止支持表示,则可以使用HTTP状态代码或自定义代码响应请求。客户端还可以验证响应的格式是否正确,并验证XML。

还有许多其他优点,我在博客上讨论了其中的一些优点:   http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

最后一个示例显示如何将版本放入URL中。假设您想要在对象内部获得一些信息,并且您已经对各种对象进行了版本化(客户是v3.0,订单是v2.0,而shipto对象是v4.2)。以下是您必须在客户端中提供的令人讨厌的URL:

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

答案 2 :(得分:99)

我们发现将版本放入URL非常实用且有用。它可以让您轻松了解您正在使用的内容。我们使用别名/ foo到/ foo /(最新版本)以便于使用,更短/更清晰的URL等,如接受的答案所示。

永远保持向后兼容通常是成本过高和/或非常困难的。我们更愿意提前通知弃用,重定向,如此处建议,文档和其他机制。

答案 3 :(得分:46)

我同意对资源表示进行版本控制更好地遵循REST方法......但是,自定义MIME类型(或附加版本参数的MIME类型)的一个大问题是写入Accept和Content-Type标头的支持不佳用HTML和JavaScript。

例如,为了创建资源,IMO无法使用HTML5表单中的以下标题进行POST:

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

这是因为HTML5 enctype属性是一个枚举,因此除了通常的application/x-www-formurlencodedmultipart/form-datatext/plain之外的任何内容都无效。

...我也不确定HTML4中的所有浏览器都支持它(它具有更宽松的encytpe属性,但是关于MIME类型是否被转发会是浏览器实现问题)

因此我觉得最合适的版本是通过URI,但我接受它不是'正确'的方式。

答案 4 :(得分:21)

将您的版本放入URI中。 API的一个版本并不总是支持另一个版本的类型,因此资源仅从一个版本迁移到另一个版本的论点是完全错误的。这与将格式从XML切换到JSON不同。这些类型可能不存在,或者它们可能在语义上发生了变化。

版本是资源地址的一部分。您正在从一个API路由到另一个API。隐藏在标题中的寻址并不是RESTful。

答案 5 :(得分:13)

您可以在REST API中进行版本控制的几个地方:

  1. 如上所述,在URI中。如果使用重定向等,这可以是易处理的,甚至是美学上令人愉悦的。

  2. 在Accepts:标题中,所以版本在文件类型中。喜欢'mp3'vs'mp4'。这也可行,虽然IMO的工作效果不如......

  3. 在资源本身。许多文件格式都嵌入了它们的版本号,通常在标题中;这允许更新的软件通过理解文件类型的所有现有版本来“正常工作”,而较旧的软件可以在指定不受支持的(较新的)版本时发挥作用。在REST API的上下文中,这意味着您的URI永远不必更改,只需要您对所交付的特定数据版本的响应。

  4. 我可以看到使用这三种方法的原因:

    1. 如果您喜欢“干净利落”的新API,或者您想要这种方法的主要版本更改。
    2. 如果您希望客户在进行PUT / POST之前知道它是否会起作用。
    3. 如果客户端必须进行PUT / POST以确定它是否能够正常工作,那就没关系。

答案 6 :(得分:8)

对REST API进行版本控制类似于任何其他API的版本控制。可以进行微小的更改,主要更改可能需要一个全新的API。最简单的方法是每次都从头开始,这就是将版本放入URL中最有意义。如果您想让客户端更轻松,您可以尝试保持向后兼容性,可以使用弃用(永久重定向),多个版本的资源等。这更加繁琐,需要更多努力。但它也是REST鼓励“酷URI不改变”的东西。

最后,它就像任何其他API设计一样。权衡客户的便利性。考虑为您的API采用语义版本控制,这使您的客户清楚地知道新版本的向后兼容性。