使用 API 优先设计创建可靠且易于使用的 API 文章摘要 API 优先设计流程 下一步是什么?特别致谢

2025-06-07

使用 API First 设计创建可靠且易于使用的 API

文章摘要

API-First 设计流程

下一步是什么?

特别感谢

最近,我需要为一位客户创建一个 API 网关。由于我是开发人员出身,API 设计对我来说是事后才考虑的事情。完成用户故事后,我编写了数据库模式,以便可以继续编写 Web 应用程序的代码。API 的开发过程是有机的,一切从当时可行的角度出发。

但正如我在项目中所了解到的,API 是人与人之间的接口(就像系统与系统之间一样)。精心设计 API 并始终坚持这些设计决策,有助于最终用户更快、更轻松地学习 API。此外,最终用户依赖 API 来创建应用程序。对这些 API 进行重大更改意味着最终用户的应用程序将面临宕机。

文章摘要

在这篇文章中,我们将讨论 API-first 思维方式如何鼓励我们将最终用户放在第一位,以便他们可以依赖简单、可靠和一致的 API。

总的来说,这个过程是这样的:

OpenAPI 3.0 定义作为 API 开发者与其最终用户之间的“契约”,从而建立了关于 API 运行方式的单一真实来源。通过这份定义 API 每个端点运行方式的“契约”,我们可以有效防范 API 发生意外的变更。

替代文本


API-First 设计流程

让我们来看看我们将为餐馆创建的简单忠诚度应用程序的设计过程。

[1] 从目标开始

我们对忠诚度应用程序的目标是让合作餐厅为顾客创建忠诚度卡,并让顾客能够赚取积分并用积分兑换物品。

设定目标为流程的后续步骤奠定了基础。它还能帮助您明确 API 的实际功能。如果您需要开发与此目标不符的功能,那么您应该考虑将其拆分为单独的应用程序。

[2] 创建用户故事

带着这个目标,让我们使用用户故事来详细说明我们的忠诚度应用程序的功能:

  • 作为最终用户:
    • 我可以在线注册会员卡
    • 我可以登录
    • 我每次与合作餐厅交易都可以赚取积分
    • 我可以在线查看我的积分余额
    • 我可以在线查看我的交易历史记录
    • 我可以查看我进行的具体交易
  • 作为餐厅经理:
    • 我可以看到我餐厅的在线卡注册情况
    • 我可以为每次注册打印一张卡片
    • 我可以将这张卡标记为已认领
    • 我可以查看我餐厅会员卡完成的交易
    • 我可以使用用户的积分进行交易
  • 作为管理员用户:
    • 我可以创建餐厅

[3] 构建领域模型

构建领域模型是将用户故事转化为对象的过程。这些对象具有属性和行为。可以将这些类视为类似于面向对象编程 (OOP) 范式中的类。

替代文本

有了这些对象,让我们思考一下它们之间的关系:

  • 用户可以拥有多张卡
  • 卡可以进行多笔交易
  • 合作伙伴可以发行多张卡(他们可以出售任意数量的会员卡)
  • 合作伙伴可以进行多项交易

为了使这些关系可操作化,我们将引入“外键”的概念。有了外键,我们将字段添加{object_name}_id到关系右侧的对象中。对于“用户可以拥有多张卡片”的关系,我们将字段添加user_id到卡片对象中。

替代文本

[4] 绘制 API 草图

准备好领域模型后,就可以开始绘制 API 草图了。千万不要急着马上开始开发 Web 应用。花点时间仔细思考一下要暴露的每个 API 端点以及 API 的资源布局。

替代文本

绘制 API 草图迫使你在投入大量开发时间之前,先想象 API 的最终样貌。绘制草图后,请将设计图展示给 API 利益相关者,并获取他们的反馈。在这个阶段,由于尚未实现任何代码,因此进行重大更改几乎无需任何成本。

了解 API 端点

要调用 API,请向服务器发送包含以下组件的请求:

  • 基本网址:loyalty-app.com
  • 路径:/cards
    • 路径的构建方式决定了资源的布局方式。卡片资源的另一种布局方式是将其嵌套在用户资源中,例如 /users/10/cards。
  • HTTP 方法:GET
  • 查询参数:?name=Raphael
  • 请求正文:
    • 它用于 POST 和其他 HTTP 方法,但不用于 GET。
  • 标题

对于我们上面的例子,当你将它们连接在一起时,请求应该是这样的:

  • GET loyalty-app.com/cards?name=Raphael

API 最佳实践

以下是一些指导原则。大多数建议并非硬性规定。最终,您需要决定哪种方案最适合您的 API。但无论您做出何种决定,都应力求在 API 设计中保持一致。

标准方法

  • 标准方法允许 API 在不同的资源之间拥有一组一致的方法。
    • 标准方法以 CRUD(创建、读取、更新、删除)为范本。标准方法列表如下。
    • 标准方法应该没有副作用。它只做它想做的事情,仅此而已。这样,我们可以在所有标准方法中保持一致的预期。例如,POST /loyalty-cards端点创建会员卡时,它不应该同时创建交易。
    • 当仅更新对象的某些部分时,最好使用 PATCH 而不是 PUT。
    • 如果您不打算实现资源的所有标准方法,您仍然应该为其构建一个端点,但让它返回 HTTP 405(方法不允许)或 HTTP 403(禁止访问)。这样,您的 API 就具有一致性。

自定义方法

  • 自定义方法允许你创建具有副作用的端点。其格式如下/{resource}/{id}:{custom_action}
    • 例如,POST /loyalty-cards/10:claim_card

使用 HTTP 状态代码

  • 使用 HTTP 状态代码来传达含义。并非所有错误都是 500 错误,也并非所有成功的操作都应该是 HTTP 200。
    • HTTP 200:
      • HTTP 201(已创建):创建资源后
      • HTTP 204(无内容):删除资源后
      • HTTP 200(OK):操作成功时捕获所有信息
    • HTTP 400:用户错误 - 用户尝试了错误的事情
      • HTTP 403(禁止访问):当您无权访问您正在访问的资源时
      • HTTP 404(未找到):
      • HTTP 400(错误请求):检查 HTTP 400 代码的完整列表,如果没有,请使用此代码作为全部代码
    • HTTP 500:服务器错误 - 服务器出现故障
      • HTTP 500:内部服务器错误 - 几乎涵盖所有应用程序错误。

针对长期运行操作的不同方法

  • 作为最佳实践,这些准则适用于始终返回时间短于 30 秒的 API 端点。如果您的端点响应时间过长,最终用户将不得不长时间等待,从而导致用户体验不佳。与其使用我们迄今为止介绍的快速响应范例,不如考虑异步处理范例。

以上就是 API 指南的简要概述。如果您想了解更多,我强烈推荐JJ Geewax 的《API 设计模式》一书。

有关标准端点的完整列表,请参阅以下使用卡片资源的列表:

标准 - 收集端点

  • 创建 - 发布/卡片
  • 阅读全部 - 获取/卡片

标准 - 资源端点

  • 阅读一篇 - 获得 /cards/10
  • 更新一个(覆盖对象) - PUT /cards/10
  • 更新一(覆盖特定方法) - PATCH /cards/10
  • 删除一张 - 删除 /cards/10

让我们学以致用

我们的任务现在变成确定我们的 API 资源布局并将每个类的方法转换为 API 端点。

对于 Cards 类,我们选择将其嵌套到用户资源中。当嵌套资源归其父资源所有时,就会创建类似的层级关系。这意味着,如果我们删除用户 #10,我们也会删除与其关联的所有卡片。如果用户 #10 违反了我们的合理使用政策,我们会禁用他的所有卡片,依此类推。

替代文本

下一步是什么?

现在,我们已经成功创建了 API 设计草图。在此阶段,我建议您将此草图展示给您的 API 利益相关者。获取他们的反馈,并在此基础上进行迭代。

在下一篇文章,我们将创建一个 Open API 3.0 定义来定义每个 API 端点的详细信息。有了这个定义,我们可以创建一个模拟

特别感谢

特别感谢 Allen,让我的文章更加条理清晰。这篇博文也感谢以下作者,他们让学习 API 变得如此快乐。

文章来源:https://dev.to/raphael_jambalos/develop-web-apps-faster-with-api-first-design-97e
PREV
我们如何使用 Amazon ECS Fargate 每月损失 800 美元但首先,介绍一下背景...这就是我们被收取如此多费用的原因...我们如何发现...小小的实验故事的寓意...
NEXT
基础设施图即代码