web服务REST API版本控制有什么已知的方法或最佳实践吗?
我注意到AWS通过端点的URL进行版本控制。这是实现同一目标的唯一途径还是其他途径?如果有多种方法,每种方法的优点是什么?
web服务REST API版本控制有什么已知的方法或最佳实践吗?
我注意到AWS通过端点的URL进行版本控制。这是实现同一目标的唯一途径还是其他途径?如果有多种方法,每种方法的优点是什么?
当前回答
有几个地方可以在REST API中进行版本控制:
如URI中所述。如果重定向等使用得当,这可能很容易处理,甚至在美学上也会令人愉悦。在Accepts:header中,因此版本在文件类型中。比如“mp3”和“mp4”。这也会起作用,尽管IMO的效果比。。。在资源本身中。许多文件格式的版本号都嵌入其中,通常在页眉中;这允许较新的软件通过理解文件类型的所有现有版本来“正常工作”,而如果指定了不受支持的(较新的)版本,则较旧的软件可以启动。在RESTAPI的上下文中,这意味着您的URI永远不需要更改,只需要您对所传递数据的特定版本的响应。
我可以看出使用这三种方法的原因:
如果您喜欢“清理”新的API,或者在需要这种方法的地方进行重大版本更改。如果您希望客户端在执行PUT/POST之前知道它是否可以工作。如果客户机必须执行PUT/POST以确定是否可以工作。
其他回答
有几个地方可以在REST API中进行版本控制:
如URI中所述。如果重定向等使用得当,这可能很容易处理,甚至在美学上也会令人愉悦。在Accepts:header中,因此版本在文件类型中。比如“mp3”和“mp4”。这也会起作用,尽管IMO的效果比。。。在资源本身中。许多文件格式的版本号都嵌入其中,通常在页眉中;这允许较新的软件通过理解文件类型的所有现有版本来“正常工作”,而如果指定了不受支持的(较新的)版本,则较旧的软件可以启动。在RESTAPI的上下文中,这意味着您的URI永远不需要更改,只需要您对所传递数据的特定版本的响应。
我可以看出使用这三种方法的原因:
如果您喜欢“清理”新的API,或者在需要这种方法的地方进行重大版本更改。如果您希望客户端在执行PUT/POST之前知道它是否可以工作。如果客户机必须执行PUT/POST以确定是否可以工作。
URL不应包含版本。版本与您请求的资源的“想法”无关。您应该尝试将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”)。这就是版本应该去的地方。每个人似乎都掩盖了这样一个事实,即你可能想要不同格式的同一件东西,而客户应该能够要求它想要什么。在上面的示例中,客户机要求资源的任何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,发货对象是v4.2)。以下是您必须在客户端中提供的讨厌的URL:
(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/
将您的版本放入URI中。API的一个版本并不总是支持来自另一个版本的类型,因此认为资源只是从一个版本迁移到另一个的说法是完全错误的。这与将格式从XML转换为JSON不同。类型可能不存在,或者它们可能在语义上发生了变化。
版本是资源地址的一部分。您正在从一个API路由到另一个API。在头中隐藏地址不是RESTful的。
我同意资源表示的版本控制更好地遵循REST方法。。。但是,自定义MIME类型(或附加版本参数的MIME类型)的一个大问题是,对HTML和JavaScript中的Accept和Content-Type头的支持较差。
例如,为了创建资源,IMO不可能使用HTML5格式的以下标头进行POST:
Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json
这是因为HTML5 enctype属性是一个枚举,因此除了通常的application/x-www-formurlconted、multipart/form-data和text/plain之外的任何属性都是无效的。
…我也不确定HTML4中的所有浏览器都支持它(它具有更宽松的encytpe属性,但对于MIME类型是否被转发,这将是浏览器实现的问题)
因此,我现在觉得最合适的版本转换方式是通过URI,但我承认这不是“正确”的方式。
REST API的版本控制类似于任何其他API的版本。小的改动可以在适当的地方完成,大的改动可能需要一个全新的API。对您来说,最简单的方法是每次都从头开始,这意味着将版本放在URL中最有意义。如果你想让客户端的生活更轻松,你可以尝试保持向后兼容性,这可以通过弃用(永久重定向)、多个版本的资源等来实现。这需要更多的努力,也更麻烦。但这也是REST在“酷URI不改变”中鼓励的。
最后,它就像任何其他API设计一样。权衡努力与客户便利。考虑为您的API采用语义版本控制,这可以为您的客户明确新版本的向后兼容程度。