【问题标题】:Supporting multiple versions of models for different REST API versions支持不同 REST API 版本的多个模型版本
【发布时间】:2021-07-22 14:39:07
【问题描述】:
是否有实施 API 版本控制的最佳实践?我对以下几点感兴趣:
- 控制器、服务 - 例如我们是否为每个版本的 API 使用不同的控制器类?新的控制器类会继承旧的控制器吗?
- 模型 - 如果 API 版本携带同一模型的不同版本 - 我们如何处理转换?例如。如果 API 的 v1 使用模型的 v1,API 的 v2 使用模型的 v2,并且我们希望同时支持两者(为了向后兼容) - 我们如何进行转换?
- 我是否可以在 Java 和 JavaScript 中将现有的框架/库用于这些目的?
谢谢!
【问题讨论】:
标签:
backwards-compatibility
api-versioning
【解决方案1】:
- 我总是建议每个 API 版本使用不同的控制器类。它使维护人员保持清洁和清晰。下一个版本通常可以通过复制和粘贴上一个版本来启动。您应该定义明确的版本控制策略;例如 N-2 个版本。通过这样做,您最终会得到 3 个并排的实现,而不是某些人认为您会遇到的爆炸式增长。在控制器之外重构非特定于 HTTP API 版本的业务逻辑和其他组件有助于减少代码重复。
- 在我看来,控制器应该绝对不从另一个控制器继承,除了具有版本中立功能(但不是 API)的基本控制器。 HTTP 是 API。 HTTP 有方法,而不是动词。将其视为
Http.get()。使用的是另一种语言,例如 Java、C# 等,是一种与 HTTP 阻抗不匹配的外观。 HTTP 不支持继承,因此尝试在实现中使用继承只会加剧不匹配问题。还有其他实际挑战。例如,您可以取消继承一个方法,这会使在继承的控制器中取消 API 的问题变得复杂(并非所有版本都是附加的)。调试也可能令人困惑,因为您必须找到正确的实现来设置断点。考虑一下版本控制策略并将责任分解到其他组件中,但根据我的经验,不需要继承。
- 模型转换是一个实现细节。这完全取决于服务器。支持转换是非常情境化的。转换可以是双向的 (
v1<->v2) 或单向的 (v2->v1)。 Mapper 是一种将一种形式转换为另一种形式的相当常见的方法。附加属性场景通常只需要旧 API 版本的存储中新属性的默认值。归根结底,对于所有场景,这个问题并没有单一的答案。
- 需要注意的是,向后兼容在 HTTP 中是用词不当。真的没有这样的事情。 API 版本是包含模型的合约。模型的新版本可以转换为模型的旧版本/从模型的旧版本转换的便利性或容易性应该被认为是方便。很容易认为附加更改具有向后能力,但服务器不能保证它与客户端一起使用。在 HTTP 的上下文中提出 backwards-capable 的概念将帮助您陷入成功的陷阱。
- 使用 Open API(以前称为 Swagger)可能是将客户端与任何语言集成的最佳选择。有一些工具可以使用该文档将客户端创建为您喜欢的编程语言。对于服务器端的 Java 库/框架,我没有具体的建议,但有多种选择。