【问题标题】:Why not to consider models in REST API versioning?为什么不在 REST API 版本控制中考虑模型?
【发布时间】:2019-10-11 17:23:54
【问题描述】:

similar question 有一个答案,但这对于一个例子来说太具体了,一般不会回答。

如果模型没有版本控制,任何人都可以告诉如何处理以下情况吗?

PUT /v1/users
username (string)
email (string) (required)
password (string) (required)
POST /v2/users
username (string) (required)
email (string) required
password (string) (required)

假设模型名称为 UserModel,在 v1 版本中用户名是可选的,但在 V2 中是必需的。

如果我们使用像 ajv 这样的模式验证器,即使 v1 api 请求也会失败,因为最新的规范/模型提到用户名是必填字段。

每个人都应该有充分的理由说不应该对模型进行版本控制,但我可能清楚地遗漏了一些东西。在这种情况下,对模型进行版本控制更有意义,因为它不会轻易破坏向后兼容性。

【问题讨论】:

  • 该架构用于请求负载,而不是持久性模型。
  • 我的模型是从 swagger 模式生成的。我想这也是怎么做的。它们确实依赖于创建模型的架构。
  • Transport 模型,也许,但如果你完全依赖数据库模式并且总是匹配 API 模式,那么这就是你会遇到的问题。
  • 如果可能的话,你能分享一个例子吗?
  • 我建议进行一些研究,这些通常称为数据传输对象 (DTO) 和数据访问对象 (DAO)。目前尚不清楚您认为编辑有什么好处。

标签: node.js express swagger versioning ajv


【解决方案1】:

您可能会将代表应用程序的模型与代表由您的 API 处理的数据的模型混淆。

这些是(或至少应该是不同的关注点,应该解耦彼此。当您在应用程序域模型中添加、删除或重命名字段时,您不希望破坏您的 API 客户端。

话虽如此,虽然您的服务层在域/持久性模型上运行,但您的 API 控制器应该在一组不同的模型上运行。

随着您的域/持久性模型不断发展以支持新的业务需求,例如,您可能希望创建 API 模型的新版本来支持这些变化。随着新版本的发布,您可能还希望弃用旧版本的 API。随着您的客户更新他们的代码,您可能会放弃对旧版本的支持。


示例

例如,假设您正在创建一个用于任务管理的应用程序。以下是您在域中表示任务的方式:

+----------------------+
|         Task         |
+----------------------+
| - id: Long           |
| - title: String      |
| - completed: Boolean |
+----------------------+

您的应用程序将提供一个 API,以便客户端可以管理他们的任务。

要在 API 中创建任务,客户端需要 POST 任务的 JSON 表示,title 和一个布尔值指示任务是否为 completed。它们不应该为id 提供值,因为它将由服务器生成。好东西。

有多种方法可以对您的 API 进行版本控制,包括 URL 和媒体类型版本控制。这是一个很大的话题,我不会在这个答案中介绍每种方法的优缺点。但是,出于示例目的,我将使用媒体类型版本控制:

POST /tasks HTTP/1.1
Host: example.org
Content-Type: application/vnd.foo.v1+json

{
  "title": "Send report to manager",
  "completed": false
}

在将应用程序发布到生产环境很久之后,您就会意识到使用布尔值来表示任务的状态并不好。并且使用带有一些值(例如 NOT_STARTEDSTARTEDCOMPLETED)的枚举将比布尔值更适合您的业务需求。

这将需要更改您的域模型和数据库。以下是您的域的样子:

+----------------------+
|         Task         |
+----------------------+
| - id: Long           |
| - title: String      |
| - status: String     |
+----------------------+

因此,您发布了 API 的新版本。任务表示现在具有 status 而不是 completed 属性:

POST /tasks HTTP/1.1
Host: example.org
Content-Type: application/vnd.foo.v2+json

{
  "title": "Send report to manager",
  "status": "NOT_STARTED"
}

那就更酷了。但是不要忘记您的应用程序已经在生产中,并且您不想破坏使用旧 API 的客户端。

因此,您将弃用旧版本的端点,但您会支持它一段时间,以便您的客户可以更新他们的代码。

将旧的任务表示映射到任务域模型时,您会考虑以下几点:

  • 如果completedtrue,那么任务status 将是COMPLETED
  • 如果completedfalse,那么任务status 将是NOT_STARTED

【讨论】:

  • 我正在使用 Swagger Codegen 来生成模型和 api 代码。如果您的意思是我需要将 swagger 中的模型与 db 模型分离,您能否就如何处理它提出一个好的工作流程?我是否需要对 swagger 生成的模式进行版本控制,并让与我的数据库直接相关的非版本模型手动编码?
  • @Ayyappa 是的。您的大多数应用程序根本不应该知道 API,它应该是关于实现所需的业务逻辑。例如,您不希望根据人们使用的 API 版本而拥有单独的数据库表,因此您如何持久保存到数据库应该是一个完全独立的问题(例如,使用 ORM)。版本化部分应该像一个模板层:将内部数据转换成不同的格式供其他人使用。
  • 感谢@IMSoP 的澄清。
  • @cassiomolin 非常感谢您花时间解释清楚。因此,可以对域生成的模型进行版本控制,但不能对数据库模型进行版本控制。对吗?
  • @Ayyappa 您可能希望对 Swagger 生成的模型进行版本控制,而不是应用程序的域模型。
猜你喜欢
  • 2016-03-08
  • 2012-05-31
  • 2021-06-22
  • 1970-01-01
  • 2018-09-30
  • 2014-08-23
  • 2013-05-17
  • 1970-01-01
  • 2018-11-08
相关资源
最近更新 更多