web服务REST API版本控制有什么已知的方法或最佳实践吗?

我注意到AWS通过端点的URL进行版本控制。这是实现同一目标的唯一途径还是其他途径?如果有多种方法,每种方法的优点是什么?


当前回答

这是一个好问题,也是一个棘手的问题。URI设计的主题同时也是RESTAPI中最突出的部分,因此是对该API用户的潜在长期承诺。

由于一个应用程序的演变,在较小程度上,它的API是一个事实,它甚至类似于一个看似复杂的产品(如编程语言)的演变,URI设计应该具有较少的自然约束,并且应该随着时间的推移而保留。应用程序和API的寿命越长,对应用程序和API用户的承诺就越大。

另一方面,生活的另一个事实是,很难预见通过API消耗的所有资源及其方面。幸运的是,没有必要设计整个API,直到天启才会使用。正确定义所有资源端点以及每个资源和资源实例的寻址方案就足够了。

随着时间的推移,您可能需要向每个特定资源添加新资源和新属性,但一旦资源寻址方案公开并因此成为最终方案,API用户访问特定资源所遵循的方法不应改变。

此方法适用于早期API版本中支持的HTTP动词语义(例如PUT应始终更新/替换)和HTTP状态代码(它们应继续工作,以便在没有人为干预的情况下工作的API客户端能够继续工作)。

此外,由于将API版本嵌入到URI中会破坏超媒体作为应用状态引擎的概念(Roy T.Fieldings博士论文中所述),因为资源地址/URI会随着时间而改变,我认为API版本不应该长期保存在资源URI中,这意味着API用户可以依赖的资源URI应该是永久链接。

当然,可以在基URI中嵌入API版本,但仅限于合理和受限的用途,如调试使用新API版本的API客户端。这种版本化的API应该是有时间限制的,并且只对有限的API用户组可用(比如在封闭测试期间)。否则,你就要在不该做的地方做出承诺。

关于维护过期的API版本的一些想法。通常用于实现web服务的所有编程平台/语言(Java、.NET、PHP、Perl、Rails等)都允许将web服务端点轻松绑定到基本URI。通过这种方式,可以很容易地收集和保持不同API版本之间的文件/类/方法的集合。

从API用户POV的角度来看,当特定的API版本很明显但仅在有限的时间内(即在开发期间)使用和绑定它也更容易。

从API维护者的POV来看,通过使用主要以文件为最小(源代码)版本控制单元的源代码控制系统,可以更容易地并行维护不同的API版本。

然而,由于API版本在URI中清晰可见,因此有一个警告:人们可能也会反对这种方法,因为API历史在URI设计中变得可见/不可见,因此随着时间的推移很容易发生变化,这违反了REST的指导原则。我同意!

解决这一合理异议的方法是在无版本API基URI下实现最新的API版本。在这种情况下,API客户端开发人员可以选择:

针对最新的API客户端进行开发(承诺维护应用程序,以保护其免受可能会破坏其糟糕设计的API客户端的最终API更改的影响)。绑定到API的特定版本(这一点很明显),但仅限于有限的时间

例如,如果API v3.0是最新的API版本,则以下两个应为别名(即,与所有API请求的行为相同):

http://shonzilla/api/customers/1234
http://shonzilla/api/v3.0/customers/1234
http://shonzilla/api/v3/customers/1234

此外,如果仍试图指向旧API的API客户端使用的API版本已过时或不再受支持,则应通知他们使用最新的先前API版本。因此,访问以下任何过时的URI:

http://shonzilla/api/v2.2/customers/1234
http://shonzilla/api/v2.0/customers/1234
http://shonzilla/api/v2/customers/1234
http://shonzilla/api/v1.1/customers/1234
http://shonzilla/api/v1/customers/1234

应返回指示重定向的30x HTTP状态代码中的任何一个,该代码与重定向到资源URI的适当版本的位置HTTP标头一起使用,该资源URI仍然是以下版本:

http://shonzilla/api/customers/1234

至少有两个重定向HTTP状态代码适用于API版本控制方案:

301永久移动,指示具有请求的URI的资源永久移动到另一个URI(该URI应该是不包含API版本信息的资源实例永久链接)。此状态代码可用于指示过时/不受支持的API版本,通知API客户端已将版本化的资源URI替换为资源永久链接。302找到,指示请求的资源暂时位于另一位置,而请求的URI可能仍受支持。当无版本URI暂时不可用时,该状态代码可能很有用,并且应该使用重定向地址重复请求(例如,指向嵌入APi版本的URI),并且我们希望告诉客户端继续使用它(例如,永久链接)。其他场景可以在HTTP 1.1规范的重定向3xx章节中找到

其他回答

我同意资源表示的版本控制更好地遵循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,但我承认这不是“正确”的方式。

我们发现将版本放在URL中既实用又有用。它可以让你一眼就知道你在用什么。如公认的答案所示,我们将/foo别名为/foo/(最新版本),以便于使用、更短/更干净的URL等。

永远保持向后兼容性通常成本高昂和/或非常困难。我们倾向于提前通知弃用、此处建议的重定向、文档和其他机制。

REST API的版本控制类似于任何其他API的版本。小的改动可以在适当的地方完成,大的改动可能需要一个全新的API。对您来说,最简单的方法是每次都从头开始,这意味着将版本放在URL中最有意义。如果你想让客户端的生活更轻松,你可以尝试保持向后兼容性,这可以通过弃用(永久重定向)、多个版本的资源等来实现。这需要更多的努力,也更麻烦。但这也是REST在“酷URI不改变”中鼓励的。

最后,它就像任何其他API设计一样。权衡努力与客户便利。考虑为您的API采用语义版本控制,这可以为您的客户明确新版本的向后兼容程度。

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

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

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

如URI中所述。如果重定向等使用得当,这可能很容易处理,甚至在美学上也会令人愉悦。在Accepts:header中,因此版本在文件类型中。比如“mp3”和“mp4”。这也会起作用,尽管IMO的效果比。。。在资源本身中。许多文件格式的版本号都嵌入其中,通常在页眉中;这允许较新的软件通过理解文件类型的所有现有版本来“正常工作”,而如果指定了不受支持的(较新的)版本,则较旧的软件可以启动。在RESTAPI的上下文中,这意味着您的URI永远不需要更改,只需要您对所传递数据的特定版本的响应。

我可以看出使用这三种方法的原因:

如果您喜欢“清理”新的API,或者在需要这种方法的地方进行重大版本更改。如果您希望客户端在执行PUT/POST之前知道它是否可以工作。如果客户机必须执行PUT/POST以确定是否可以工作。