我正在使用REST API,因此我必须尽快引入一些重大更改,因此需要v2。尽管仍并行支持v1,但仍需要几个月的时间,以便让我们的客户有时间在准备好新版本时切换到新的API。我们的API是通过共享云提供的,并且我们所有的客户都共享相同的系统后端,尤其是单个共享数据库。
我找到了很多有关REST API版本控制的文章,但它们更多是从客户端的角度或从高级设计的角度来看的。这并不是我真正关心的问题,因为我们的API已经在URI中提供了版本控制,所以提供带有/ v2基本路径的服务将不是问题。
但是我问自己如何真正实现此目标,而我还没有真正找到好的文章。我真的不想分支我的项目的v2,然后将v1和v2分别构建和部署为单独的应用程序,因为那样的话,我将在两个应用程序中进行维护,错误修复,配置更改等,这是双重工作并且通常冗余的危险(即:版本之间可能存在不一致)。此外,v2当然在每个服务中也不相同,因此大多数代码仍将相同。
在如何在向外部提供多个版本以及共享一些代码的单个应用程序中技术上实现REST API方面是否存在最佳实践(例如:v2 / someService将在内部重定向到v1 / someService),以及只是实际的差异被编码在新服务中?也许甚至还有一些框架可以帮助您设计?如果有帮助,该应用程序使用Spring MVC用Java编码。
感谢您提供有关解决此问题的任何提示或资源。谢谢!
答案 0 :(得分:0)
如果遇到您遇到的情况,我将首先尝试使新版本(v2)与我的第一个版本(v1)向后兼容。如果是这种情况,您只需添加功能并更新API文档,仅保留一个活动的代码库即可。我认为您甚至可以在响应有效负载中添加内容,只要返回的数据不会破坏任何人的代码-就像在现有数据库模式中添加字段一样。
如果v2与v1不向后兼容,则可以将v1移至另一台服务器,并通知您用户将其放置在指定的有限时间内,以便他们有时间进行更改代码以切换到v2,但也要通知他们该版本已不再更新,如果他们遇到问题,则需要切换到新版本。因此,v2是您的代码库的HEAD版本,没有其他分支处于活跃开发中。
我希望这会有所帮助,并提供您尚未想到的东西。
答案 1 :(得分:0)
希望您见过
在同一应用程序中具有两个版本的API足够安静
api.mysite.com/ [version1] / api / url
api.mysite.com/ [version2] / api / url
不确定是否需要将v1和v2分别构建和部署为单独的应用程序?除非您计划在生产中进行零停机滚动升级
答案 2 :(得分:0)
我喜欢在讨论中提出以下策略,这两个都是Continuous Delivery中的策略。
分支抽象
基本思想是在客户端和您当前的实现之间放置一个抽象层。然后在抽象层后面介绍第二种实现。这使您有机会在常规代码库中进行升级,但立即为下一版本的API支持新功能。
https://martinfowler.com/bliki/BranchByAbstraction.html
功能切换
将功能添加到您的代码库中,而对客户不可见。即使最终用户还没有准备好,这也可以让您留在主要的开发分支中。
答案 3 :(得分:0)
我现在也面临这样的任务,仍然没有有用的答案。虽然我相信并行使用单独的 v1 和 v2 实例仍然至少是一种后备解决方案,但我目前正在考虑针对单个应用程序的方案,该方案将大量利用应用程序中依赖注入的好处。因此,基本上的想法是根据收到的请求配置您的 IoC 容器,以便每个服务都会收到其依赖项的所需版本。这在理论上是一个很好的解决方案,但它需要一个已经接近理想的应用程序架构(通常情况并非如此),所有关注点都被分离等。换句话说,尽可能可靠。至少通过这种方法,您将能够快速识别代码库中需要重构的所有组件,尽管整个过程不是一个快速的过程。此外,我相信更改越接近应用程序的核心,并行版本控制可能就越困难,但会看到。
我应该再次指出,对我来说,这仍然只是一个想法,我将专门为我的项目进一步研究,所以我不确定它实际上有多容易或有多困难。
答案 4 :(得分:-1)
v1 / v2难题很明显地表明您实际上没有REST API。 REST体系结构中的对等方通过客户端请求他们理解的媒体类型的表示来交换或多或少的标准化内容。这种技术称为内容类型协商。当然,写得不好的服务器可能会忽略建议的媒体类型,并发送客户端不理解的媒体类型。但是,这将阻止客户端进一步与服务器交互。因此,行为良好的服务器应尝试尽最大可能满足客户请求。
根据Fielding:
REST API应该花费几乎所有的描述性精力来定义用于表示资源和驱动应用程序状态的媒体类型,或者为现有标准媒体定义扩展关系名称和/或启用超文本的标记类型。花费所有精力描述应该在媒体类型的处理规则范围内(并且在大多数情况下已由现有媒体类型定义)完全定义要在感兴趣的URI上使用的方法。 [失败在这里表示带外信息正在驱动交互,而不是超文本。。]
Source
一种媒体类型描述了为这种媒体类型交换的有效负载的语法以及该表示形式中每个元素的语义。在有意义的链接关系名称和媒体类型的帮助下,服务器可以指导客户有关客户端在执行任务时可以利用的下一个可用选项。即考虑一下以前的响应包含到客户端的链接关系create
的情况。客户端并不真正知道必须如何处理才能由服务器处理,请通过调用为create
链接关系名称返回的URI进行响应,服务器以{ {1}},其中此媒体类型定义了一些客户端可以使用的输入控件,以便生成服务器在目标端点上期望的请求表示形式。与Web相似,自定义表单还包含HTTP操作以及客户端提供的目标URI,以将响应发送到服务器,并最终还发送服务器首选的表示形式。
REST体系结构中的客户端不必关心URI,因此返回包含application/vnd.xyz-form+json
或v1
的URI对他们而言或多或少毫无意义。菲尔丁甚至说a REST API itself shouldn't be versioned at all!但是,重要的是客户端和服务器能够理解收到的有效负载。
代替对URI或API进行版本控制,描述语法和语义的媒体类型实际上需要进行版本控制。即如果您看一下基于浏览器的Web(REST的大同胞),尤其是HTML,那么您会发现它的设计要求新版本保持向后兼容。即接收到v2
定义的有效负载的客户端和服务器将能够处理多达HTML5内容的纯HTML(1.0),无论使用了哪种实际语法(甚至可能是混合语法)。但是,其他媒体类型可能不会那么宽容。如果您认为新旧媒体完全不兼容,则可以使用配置文件或注册一种全新的媒体类型。
无论哪种方式,我都希望我能对REST体系结构以及您如何实现它有更多的了解。我很清楚我的建议可能并不容易实现,尽管一旦获得建议,您就可以将客户端与API分离开来,并为后者提供发展的自由,而不必担心破坏客户端。仍然存在耦合,但是客户端和服务器都将耦合到媒体类型,而不是彼此耦合。在创建新的媒体类型之前,可能值得寻找already existing ones