17

我正在开发一个 REST API,我将不得不很快引入一些重大更改,因此需要 v2。我们仍然需要同时支持 v1 几个月,以便让我们的客户有时间在他们准备好时切换到新的 API。我们的 API 是通过共享云提供的,我们所有的客户共享相同的系统后端,尤其是单个共享数据库。

我发现了很多关于 REST API 版本控制的文章,但它们更多是从客户端的角度或高级设计的角度来看的。这不是我真正关心的问题,我们的 API 已经在 URI 中进行了版本控制,因此提供具有 /v2 基本路径的服务不会有问题。

但是我问自己我将如何实际实现这一点,我还没有真正找到关于这方面的好文章。我真的不想分支我的项目的 v2,然后将 v1 和 v2 构建和部署为单独的应用程序,因为那样我将在两个应用程序中进行维护、错误修复、配置更改等,这是双重工作并且进行通常的冗余的危险(即:版本之间可能存在不一致)。此外,v2 当然在每个服务中都没有不同,所以大部分代码仍然是相同的。

是否有关于如何在向外部提供多个版本的单个应用程序中技术实现 REST API 以及共享一些代码的最佳实践(即:v2/someService 将在内部重定向到 v1/someService),以及实际差异编码在新服务中?也许甚至有框架可以帮助设计这个?如果有帮助,该应用程序将使用 Spring MVC 用 Ja​​va 编码。

我感谢有关如何解决此问题的任何提示或资源。谢谢!

4

5 回答 5

1

我喜欢在讨论中提出以下策略,它们都是持续交付中的策略。

分支抽象

基本思想是在客户端和当前实现之间放置一个抽象层。然后在抽象层后面引入第二个实现。这使您有机会在您的正常代码库中取得进展,但立即支持您的下一个版本 API 的新功能。

https://martinfowler.com/bliki/BranchByAbstraction.html

功能切换

将功能添加到您的代码库中,但不会让您的客户看到它们。这允许您留在您的主要开发分支上,即使事情还没有为最终用户准备好。

https://martinfowler.com/articles/feature-toggles.html

于 2019-06-25T08:00:57.167 回答
1

希望你已经看到

  1. 确保向后兼容性的 API 设计
  2. http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/32713.pdf

在同一个应用程序中拥有两个版本的 API 足够安静

api.mysite.com/[version1]/api/url

api.mysite.com/[version2]/api/url

不确定为什么需要将 v1 和 v2 作为单独的应用程序构建和部署?除非您计划在生产中进行零停机时间滚动升级

于 2018-10-24T11:57:38.717 回答
0

如果我遇到你所说的情况,我会首先尝试保持我的新版本(v2)与我的第一个版本(v1)向后兼容。如果是这种情况,您可以只添加功能并更新您的 API 文档,只保留一个活动代码库。我认为只要返回的数据不会破坏任何人的代码,您甚至可以将内容添加到响应有效负载中 - 有点像将字段添加到现有数据库架构中。

如果 v2 与 v1 不向后兼容,您可以将 v1 移动到另一台服务器并通知您的用户它被放置在那里一段规定的、有限的时间,让他们有时间进行必要的代码更改以切换到 v2,但也通知他们说这个版本不再更新,如果他们有问题,他们将需要切换到新版本。因此,v2 是您的代码库的 HEAD 版本,没有其他正在积极开发的分支。

我希望这会有所帮助并提供您尚未想到的东西。

于 2018-10-23T22:56:17.533 回答
0

我现在也面临这样的任务,仍然没有有用的答案。虽然我相信并行单独的 v1 和 v2 实例至少仍然是一种后备解决方案,但我目前正在考虑一个单一应用程序的方案,它将在应用程序中大量使用依赖注入的好处。因此,基本上想法是根据接收到的请求配置您的 IoC 容器,以便每个服务都会收到其依赖项的所需版本。从理论上讲,这可能是一个很好的解决方案,但它需要您的应用程序已经接近理想的架构(通常不是这种情况),其中所有关注点都被分离等等。换句话说,尽可能可靠。至少通过这种方法,您将能够快速识别代码库中需要重构的所有组件,尽管使整个过程不是一个快速的过程。此外,我相信更改越接近应用程序的核心,并行版本控制可能就越困难,但会看到。

我应该再次指出,对我来说,这仍然只是一个想法,我将专门针对我的项目进一步研究,所以我不确定它实际上会有多容易或有问题。

于 2021-07-06T08:58:12.693 回答
-5

v1/v2 困境强烈暗示您实际上没有 REST API 可以开始。REST 架构中的对等点通过客户端请求他们理解的媒体类型的表示来交换或多或少的标准化内容。这种技术称为内容类型协商。当然,一个写得不好的服务器可能会忽略建议的媒体类型并发送一个客户端不理解的。但是,这将阻止客户端与服务器进一步交互。因此,表现良好的服务器应该尽可能地尝试为客户端请求提供服务。

根据菲尔丁的说法:

REST API 应该花费几乎所有的描述性工作来定义用于表示资源和驱动应用程序状态的媒体类型,或定义扩展关系名称和/或现有标准媒体类型的超文本启用标记。描述在感兴趣的 URI 上使用哪些方法所花费的任何努力都应该完全在媒体类型的处理规则范围内定义(并且在大多数情况下,已经由现有媒体类型定义)。[这里的失败意味着带外信息正在推动交互而不是超文本。]
来源

媒体类型描述了为这种媒体类型交换的有效负载的语法以及该表示中每个元素所具有的语义。在有意义的链接关系名称和媒体类型的帮助下,服务器可以向客户端介绍下一个可用的选项,客户端可以在完成其任务时使用。即考虑以前的响应包含create与客户端的链接关系的情况。客户端并不真正知道某些东西必须是什么样子才能被服务器处理,但在调用为create链接关系名称返回的 URI 时,服务器会以类似形式的表示形式进行响应application/vnd.xyz-form+json此媒体类型定义了一些输入控件,客户端可以使用这些控件在目标端点上生成服务器期望的请求表示。与 Web 类似,自定义表单还包含 HTTP 操作以及客户端提供的目标 URI,以将响应发送到服务器,最终还包含服务器首选的表示形式。

REST 架构中的客户端不应该关心 URI,因此返回包含v1or的 URIv2对他们来说应该或多或少毫无意义。Fielding 甚至表示REST API 本身根本不应该进行版本控制!重要的是客户端和服务器能够理解接收到的有效负载。

实际上需要对描述语法和语义的媒体类型进行版本控制,而不是对 URI 或 API 进行版本控制。即,如果您查看基于浏览器的 Web(REST 的大兄弟),尤其是此处的 HTML,您会注意到它的设计方式要求新版本保持向后兼容。即客户端和服务器接收text/html定义的有效负载将能够处理纯 HTML (1.0) 到 HTML5 内容,无论使用哪种实际语法(甚至可能是混合语法)。但是,其他媒体类型可能不会那么宽松。如果您认为新旧媒体类型完全不兼容,您可以在这里使用配置文件或注册全新的媒体类型。

无论哪种方式,我希望我能对 REST 架构以及如何实现这一点有更多的了解。我很清楚我的建议可能并不容易实现,尽管一旦你得到它,你基本上将客户端与你的 API 解耦,并让后者自由发展,而不必担心破坏客户端。仍然会有耦合,但客户端和服务器都会耦合到媒体类型,而不是彼此耦合。在创建新的媒体类型之前,可能值得寻找已经存在的媒体类型

于 2018-10-24T00:31:51.947 回答