NestJS 架构设计系列:掌握 API 接口定义的方法论

41 阅读5分钟

背景

不知道你是否也有过这样的习惯,当我们在阅读一个产品的开放 API 文档时,会不自觉地从其可读性与规范性来判断该团队技术的专业程度。因为从本质上看,API 定义与团队的工程规范以及数据库表结构息息相关,高质量的 API 定义,往往意味着背后有良好的数据模型与领域设计。反之,则容易暴露出系统结构上的混乱。

那么如何定义高质量的 API 接口?估计你会立马会想到 RESTful API(Representational State Transfer),RESTful API 是目前最流行的接口设计风格,它通过对资源的抽象来定义系统的数据结构与行为,在 RESTful API 中,每个资源都有一个唯一的 URL,而 HTTP 方法(如 GET、POST、PUT 和 DELETE)则用于定义对该资源的操作。

RESTful API 的设计规范好像已经非常清晰,这样看似乎我们已经掌握了 API 接口定义的方法论,但实际落地中你会发现,在面对复杂业务场景时,依然会遇到拿不准接口路径该如何定义字段如何命名的尴尬。有的场景很适合 RESTful,有的却模棱两可,还有的完全无法用 RESTful 的方式优雅表达。

本篇文章将通过一个典型的接口定义场景,带你掌握 API 接口定义的方法,理解这套方法后,你将能在面对各种接口定义难题时游刃有余、从容决策。

数据导入接口定义场景

需求背景

假设你接到一个新需求:需要开发一个接口数据导入接口。目标是将外部或历史系统的接口定义(API 接口规范、接口列表、接口文档、Schema 等) 导入到当前平台中。该导入接口应具备以下能力:

  • 支持多种类型的数据导入:例如 OpenAPI(Swagger)、GraphQL Schema、gRPC/Protobuf、RPC 描述或自定义接口清单;
  • 可配置导入选项:字段映射、示例数据策略、路径处理方式、校验规则等;
  • 版本与命名冲突处理:支持覆盖、新版本创建、自动合并、冲突提示等机制。

竞品调研

拿到以上的需求后,如果你不是一位非常资深的开发,第一步不要立刻按照自己的习惯去设计接口,而是先研究行业内成熟工具的做法。尤其推荐优先参考海外优秀竞品,它们在标准化和工程实践上往往更成熟。

Postman

在调研 Postman 竞品的开放接口中,我们看到了导入接口 /import/openapi?workspace={{workspaceId}} 的定义,相关链接:Postman API 导入

image.png

这里我们可以学习几点:

  • 路径命名采用 import,很语义化,是一个重要参考;
  • 请求体采用清晰的分层结构:
{
    "type": "{{APIspecificationType}}",
    "input": "{{APIspecification}}",
    "options": {
        "{{optionName}}": "{{optionvalue}}"
    }
}
  • input 支持多种数据类型(文件、URL、直接文本、JSON/YAML);
  • options 导入选项较为丰富,如:
"options": {
  "folderStrategy": "Path",
  "disableOptionalParameters": true,
  "exampleParametersResolution": "Schema"
}

Stoplight

Stoplight 没有看到提供导入开放 API,但其导出 API 有值得借鉴之处,导出接口链接为:Stoplight API 导出

image.png

我们能收获到接口路径的命名和字段规范:

  • 路径规范/projects/{project_id}/branches/{branch_name},说明其操作资源均明确归属于某个项目/分支;
  • 字段命名使用下划线风格:如 include_internal
  • 提到 Stable IDs 的概念概念:确保文档或 API 内容在移动、重命名或变更后,其对外发布的 URL 不会改变,从而避免链接失效。

ReadyAPI

ReadyAPI 虽未提供导入 API,但从其文档 Working With PostmanExporting APIs 中可参考:

  • 支持 OAS 版本选择、认证方式、进阶导入选项:OAS versioncredentialsadvanced options
  • 对不同 API 定义类型(Definition Types)可抽象为 protocol

RapidAPI

RapidAPI 是 GraphQL 平台 API,没有看到相关导入的接口,不过在其他文档介绍中收获到支持 scope 控制,可以导入完整 API 或仅选择部分 API,实现更精细的资源范围选择方式:

image.png

README

README 有导入相关接口:上传 API 规范,参数命名更倾向使用 spec,而非 data

image.png

设计过程和思路

有了以上竞品参考后,这时我们就可以针对我们的需求进行接口定义了。

接口路径设计

导入的资源属于某个项目,因此路径可设计为:

POST /projects/{project_id}/import

表达资源的归属关系。

请求结构设计

建议采用分层结构,清晰、可扩展:

{
  "type": "OpenAPI",
  "input": { ... },
  "options": { ... }
}

输入类型

input 可支持多种数据类型:URL、内嵌 JSON/YAML。

导入选项

结合以上竞品经验,导入选项定义如下:

  • 结构转换选项

    • folderStrategy(文件夹结构映射方式);
    • exampleParametersResolution(示例参数解析策略)。
  • 数据约束选项

    • disableOptionalParameters(忽略可选参数);
    • include_internal(是否包含内部资源)。
  • 范围控制(scope)

    • 部分导入、跳过某些 tag/route。
  • 冲突处理机制(非常关键):

  • 限流与错误处理

    • 应提供 rateLimited 错误说明,返回详细的校验报告,指导用户如何处理限流。
  • Stable ID 支持:

    • 引入 stable_id 概念,避免导入过程中资源 ID 改变造成链接失效。

其他优质 API 参考

在设计整个接口体系时,可以持续参考下面这些成熟产品的 API 规范:

总结

通过本篇文章,相信你已经掌握了从需求分析竞品调研API 设计 的完整方法。以后面对各种复杂的接口定义场景,你将能够设计出结构合理、语义清晰、扩展性强的 API,再也不用担心自家产品的开放 API 被别人吐槽。如果你觉得有更好的方法或者有什么地方遗漏、疑惑,欢迎评论讨论。