Rest 如何管理版本化API的底层代码库?

Rest 如何管理版本化API的底层代码库?,rest,versioning,api-versioning,Rest,Versioning,Api Versioning,我一直在阅读RESTAPI的版本控制策略,其中似乎没有一个涉及到如何管理底层代码库 假设我们正在对API进行一系列突破性的更改—例如,更改我们的客户资源,使其返回单独的名字和姓氏字段,而不是单个名字字段。(对于本例,我将使用URL版本控制解决方案,因为它很容易理解所涉及的概念,但这个问题同样适用于内容协商或自定义HTTP头) 我们现在在http://api.mycompany.com/v1/customers/{id},以及位于http://api.mycompany.com/v2/custom

我一直在阅读RESTAPI的版本控制策略,其中似乎没有一个涉及到如何管理底层代码库

假设我们正在对API进行一系列突破性的更改—例如,更改我们的客户资源,使其返回单独的
名字
姓氏
字段,而不是单个
名字
字段。(对于本例,我将使用URL版本控制解决方案,因为它很容易理解所涉及的概念,但这个问题同样适用于内容协商或自定义HTTP头)

我们现在在
http://api.mycompany.com/v1/customers/{id}
,以及位于
http://api.mycompany.com/v2/customers/{id}
。我们仍在发布v1api的错误修复和安全更新,但新功能开发现在都集中在v2上。我们如何编写、测试和部署对API服务器的更改?我至少可以看到两种解决方案:

  • 对v1代码库使用源代码管理分支/标记。v1和v2是独立开发和部署的,在必要时使用修订控制合并将相同的错误修复应用于这两个版本-类似于在开发主要新版本的同时仍然支持以前的版本时如何管理本机应用程序的代码库

  • 让代码库本身知道API版本,这样您就得到了一个包含v1客户表示和v2客户表示的代码库。将版本控制视为解决方案体系结构的一部分,而不是部署问题—可能使用名称空间和路由的某种组合来确保请求由正确的版本处理


分支模型的明显优点是删除旧的API版本非常简单—只需停止部署适当的分支/标记—但如果运行多个版本,则最终可能会出现非常复杂的分支结构和部署管道。“统一的代码库”模型避免了这个问题,但是(我认为?)当不再需要不推荐的资源和端点时,从代码库中删除它们会变得更加困难。我知道这可能是主观的,因为不太可能有一个简单的正确答案,但我很想了解跨多个版本维护复杂API的组织是如何解决这个问题的

你提到的两种策略我都用过。在这两种方法中,我倾向于第二种方法,在支持它的用例中更简单。也就是说,如果版本控制需求很简单,那么使用更简单的软件设计:

  • 变更次数少、变更复杂度低或变更计划频率低
  • 在很大程度上与代码库的其余部分正交的更改:公共API可以与堆栈的其余部分和平共存,而无需在代码中进行“过度”(无论您选择采用哪个术语定义)分支
我发现使用此模型删除不推荐的版本并不太困难:

  • 良好的测试覆盖率意味着剥离失效的API和相关的支持代码可以确保没有(很好,最小的)回归
  • 良好的命名策略(API版本化的包名,或者方法名中更难看的API版本)使查找相关代码变得容易
  • 跨领域的关注更加困难;为了支持多个API而对核心后端系统进行的修改必须非常仔细地权衡。在某种程度上,后端版本控制的成本(请参阅上面关于“过度”的评论)超过了单个代码库的好处
从减少共存版本之间冲突的角度来看,第一种方法当然更简单,但维护单独系统的开销往往超过减少版本冲突的好处。这就是说,建立一个新的公共API堆栈并开始在一个单独的API分支上进行迭代非常简单。当然,代际流失几乎立刻就开始了,分支变成了一堆合并、合并冲突解决和其他类似的乐趣

第三种方法是在体系结构层:采用Facade模式的变体,将api抽象到面向公众的、版本化的层中,这些层与适当的Facade实例对话,后者通过自己的api集与后端对话。您的Facade(我在以前的项目中使用了一个适配器)变成了它自己的包,自包含且可测试,并且允许您独立于后端迁移前端API,也允许您相互迁移前端API

如果您的API版本倾向于公开相同类型的资源,但具有不同的结构表示,如您的全名/名/姓示例中所示,这将起作用。如果他们开始依赖不同的后端计算,这会稍微困难一些,比如,“我的后端服务返回的复利计算不正确,已在public API v1中公开。我们的客户已经纠正了这种错误行为。因此,我无法在后端更新该计算并在v2之前应用它。幸运的是,这种情况很少发生:实际上,RESTful API的消费者更喜欢准确的资源表示,而不是bug,以实现bug向后兼容性,即使在理论上幂等的
GET
ted资源上的非破坏性更改中也是如此


我很想听听您的最终决定。

分支对我来说似乎更好,我在我的案例中使用了这种方法

是的,正如您已经提到的那样-后移植bug修复将需要一些努力,但同时支持一个源库下的多个版本(包括路由和所有其他内容)将需要您付出更少的努力,但至少是同样的努力,使系统更加复杂和可怕,内部有不同的逻辑分支(在某一点上)