当前位置:  开发笔记 > 编程语言 > 正文

API版本控制的最佳实践?

如何解决《API版本控制的最佳实践?》经验,为你挑选了7个好方法。

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

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



1> Shonzilla..:

这是一个很好而且棘手的问题.URI设计的主题同时也是REST API中最突出的部分,因此可能是对该API用户的长期承诺.

由于应用程序的演变以及在较小程度上它的API是生活中的事实,并且它甚至类似于看似复杂的产品(如编程语言)的演变,因此URI设计应该具有较少的自然约束并且应该保留一段时间.应用程序和API的生命周期越长,对应用程序和API用户的承诺就越大.

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

随着时间的推移,你可能需要新的资源和新的属性添加到每个特定的资源,但API遵循用户访问特定资源的方法不应改变,一旦资源寻址方案成为公众,因此决赛.

此方法适用于HTTP动词语义(如PUT应该总是更新/更换),而且在早期版本的API支持HTTP状态代码(他们应该继续工作,这样无需人工干预工作过的是API客户端应能继续工作像那样).

此外,由于嵌入的API版本到URI会扰乱这个概念超媒体作为应用状态的引擎由具有资源地址/ URI会随时间而改变(在罗伊T. Fieldings博士论文说),我可以得出结论,API版本不应该被保存在资源的URI很长一段时间这意味着该API的用户可以依靠应该永久链接资源的URI.

当然,可以在基本URI中嵌入API版本,仅限于合理和受限制的用途,例如调试与新API版本一起使用的API客户端.此类版本化API应该是有时间限制的,并且仅限于有限的API用户组(例如在封闭的测试版中).否则,你会把自己投入到你不应该做的地方.

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

从API用户POV开始,当它显而易见但仅在有限的时间内(即在开发期间)时,它也更容易使用并绑定到特定的API版本.

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

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

解决这个合理异议的方法是在无版本API基URI下实现最新的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状态代码,这些代码LocationHTTP头一起使用,重定向到仍然属于这个的资源URI的适当版本:

http://shonzilla/api/customers/1234

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

301永久移动,指示具有请求的URI的资源永久移动到另一个URI(应该是不包含API版本信息的资源实例永久链接).此状态代码可用于指示过时/不受支持的API版本,通知API客户端已将版本化资源URI替换为资源永久链接.

302 Found表示所请求的资源暂时位于另一个位置,而仍可支持请求的URI.当无版本的URI暂时不可用并且应该使用重定向地址重复请求时(例如,指向嵌入了APi版本的URI)并且我们想要告诉客户端继续使用它(即固定链接).

其他方案可以在HTTP 1.1规范的重定向3xx章节中找到


当底层实现发生变化时,不应将URL中的版本号视为不良做法."当服务接口以非向后兼容的方式改变时,实际上已经创建了一个全新的服务......从客户端的角度来看,服务只不过是一个接口和一些非功能性质. .如果服务接口以非向后兼容的方式发生变化,它就不再代表原始服务的实例,而是一种全新的服务." http://www.ibm.com/developerworks/webservices/library/ws-version/
对于最后一部分:我会说一个过时且不再受支持的API应该返回"410 Gone",因为重定向可能表示新位置不兼容.如果API只是过时但仍然存在,则响应中的"警告"HTTP标头可能是一个选项.
您如何处理已经使用稳定URL的客户端,例如http:// shonzilla/api/customers/1234,并且您想要升级到新版本?你如何强迫他们将V2(旧的)添加到URL?
另请参阅使用Accept标头指示客户端期望的版本:http://blog.steveklabnik.com/2011/07/03/nobody-understands-rest-or-http.html
您是否有任何想法添加标题版本号,以便客户或开发人员检查?
请不要将重定向放在REST API上 - 处理它们非常痛苦,因为浏览器会自动强制它们,即使它们导致跨域错误.
有些情况下,URL上的API版本必须是必须的.如果要从浏览器中执行的JavaScript客户端访问您的API,则很可能您的用户群的大多数浏览器不支持CORS并且将使用JSONP来访问您的API .JSONP仅支持GET方法而您无法操纵标题.因此,如果您提供这种风格,您的API版本控制策略应该关注URL.
HATEOAS没有指定版本控制资源的任何内容.我认为在语义上,是的,在Accept标头中的版本化更有意义,但从实际意义上讲,我总是发现在URI中处理具有版本的API(浏览,使用curl等)更容易.所以,语义被诅咒.3流行REST API的好例子(恕我直言)http://developer.github.com/v3/ http://www.twilio.com/docs/api/rest https://stripe.com/docs/api
我强烈反对在URI中添加版本号会破坏HATEOAS.事实上,如果您已正确实施HATEOAS,那么根据定义,向您的URI添加版本控制无关紧要......客户端完全不受影响.
而不是http:// shonzilla/api/customers/1234我将使用http:// shonzilla/api/latest/customers/1234只是为了明确表示它有时可能会破坏它们的代码.人们更容易使用http:// shonzilla/api/3/customers/1234.其余的,我同意
从理论上讲,这是一个好主意,除非请求要么通过某些代理服务器,要么API服务器在CDN(如Akamai)后面,因为那些可能会过滤掉一些HTTP标头.使用标准标题("走私"API版本,例如Server:SomeAPI/2.1)而不是自定义标题(例如X-API-Version:2.1)是一个好主意.无论如何,您需要与您的提供商进行验证,并在强制您的客户使用标题之前要求做出某种长期承诺.
在我看来,要保持宁静的版本应该在资源层面考虑,在网址的后期而不是早期.API的概念就是保存资源的上下文.您可以拥有一个资源的两个版本但只有一个资源,不同版本的资源实际上是两个不同的资源,因为它们可以有不同的形状,您需要知道您正在使用客户v2而不是v1.在url级别添加版本作为资源的扩展可以帮助您:shonzilla/api/customers.v2/1234

2> 小智..:

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

  Neil Armstrong

标题包含包含您要求的表示的行("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

  Neil Armstrong

此外,假设客户认为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/


XML表示 - 实际上并不是它想要的真实表示.理论上,服务器可以返回与请求完全无关的内容,只要它是XML并且必须进行解析才能意识到它是错误的.
我不能同意这一点,至少是你最后的理由.这似乎是说URI的不同部分有不同的版本.但这不是API版本的重点.关键是ENTIRE资源有一个版本.如果您更改版本,则它是不同的API资源.这就是为什么看到http://company.com/api/v3.0/customer/123/v2.0/orders/4321/而不是http://company.com/api/v3没有意义. 0/customer/123/orders/4321 /您没有对资源的任何给定部分进行版本控制,而是对整个资源进行版本控制.
在语句中使用标题中的版本号似乎更好.但是使用URL更加实用:不易出错,最容易被开发人员看到,在休息测试客户端中很容易修改.
在Accept标头中处理独立数据协定版本和服务合同版本似乎很麻烦,因为它在URL中很麻烦.还有其他选择吗?此外,如果我有多个端点(soap,rest),是否也应该在接受中指示并让服务器端的路由服务决定到正确端点的方向或者是否可以在URL中编码端点?
我认为BAD/GOOD over简化了这个问题.API代表"应用程序编程接口",版本控制接口似乎是一个非常好的主意.API并不仅仅是提供资源.需要分离的是,有些人在谈论界面,而其他人在谈论资源.如果您在网络标签中仔细查看google maps api,您会看到它们在网址中包含api版本号.例如:身份验证期间的maps.google.com/maps/api/jsv2.jsv2是api号码.
@Gili:实际上,您不应再使用`-x`,因为[RFC6648](http://tools.ietf.org/html/rfc6648)已弃用它.
我同意,有三个更正:1.您必须对整个URI进行版本控制(因此您的上一个示例没有意义).2.您应该使用`x-`而不是`vnd.因为后者必须在IANA注册.3.您应该使用`Content-Type:x-com.company.myapp + json;来分隔内容类型和版本.版本= 5`.
我可以想到在url中执行此操作的另一个原因是,您可以使用更多REST框架将路由功能从"架子"中移除,而如果您使用Headers for Routing,则必须覆盖默认路由实现,并在顶部使用头路由网址路由.随着回到别人的点.Api是语义的,如果意义改变,它现在是一个不同的资源,应该如此路由.

3> Yoav Shapira..:

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

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


接受的答案可能是正确的,也是最纯粹的.但是,对于API的开发人员和日常用户来说,这肯定是最容易使用和设置的.最务实的方法.正如其他谷歌和亚马逊所表明的那样,也使用这种方法
facebook在网址中进行版本控制:https://blog.apigee.com/detail/restful_api_design_tips_for_versioning

4> Kevsy..:

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

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

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

这是因为HTML5 enctype属性是一个枚举,因此任何其他比平常application/x-www-formurlencoded,multipart/form-data并且text/plain是无效的.

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

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


假设在标题中定义了版本控制的路由,可以说使用本机表单提交的HTML表单将始终使用最新版本的API,因为它们不会传递他们想要遵循的特定版本.但是,XHR请求确实允许您更改接受并读取内容类型标头.所以基本形式确实是唯一的问题.
@Kyle,我在某个地方看到一个博客说如果你没有在请求标题中特定的版本,最好返回第一个api版本而不是最新版本的最佳兼容版本.

5> Sean O'Dell..:

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

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



6> pjz..:

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

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

    在Accepts:标题中,因此版本在filetype中.喜欢'mp3'vs'mp4'.这也可行,虽然IMO的工作效果不如......

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

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

    如果您喜欢"干净扫描"新API,或者您希望采用这种方法进行主要版本更改.

    如果您希望客户端在进行PUT/POST之前知道它是否能够正常工作.

    如果客户端必须执行其PUT/POST以确定它是否能够正常工作,那就没关系了.



7> Alexander To..:

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

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

推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有