如何设计API接口

前后端协作的效率,很大程度上取决于 API 接口的质量。一个设计良好的 API,让前端开发者看到路径就知道资源是什么,看到方法就知道做什么操作,看到状态码就知道结果如何。反之,命名混乱、响应格式随意、错误信息含糊的接口,则会消耗大量沟通成本。

在 AI 产品出海场景中,API 的重要性更加突出。你的后端服务可能需要对接海外多个前端团队、第三方集成平台、甚至开放给外部开发者。一套清晰、规范、可预期的 API 设计,是降低协作摩擦的基础设施。

本文从 RESTful 核心原则出发,系统讨论路由设计、请求响应格式、版本管理策略和 API 文档编写,帮助你建立可落地的 API 设计规范。

RESTful 设计原则

REST(Representational State Transfer)不是一种协议,而是一种架构风格。它的核心思想是:将服务端暴露的内容抽象为「资源」,通过统一的接口对这些资源进行操作。理解 REST 的关键,不在于记住一堆规则,而在于把握三个基本约束。

资源导向

REST 的第一原则是「一切皆资源」。用户、订单、文章、评论、AI 生成的漫画剧本——这些都是资源。每个资源通过一个唯一的 URI(Uniform Resource Identifier)来标识。

# 资源的 URI 应该用名词,而不是动词
# ✅ 正确
GET /api/users
GET /api/comic-scripts/abc123

# ❌ 错误
GET /api/getUsers
GET /api/fetchComicScript?id=abc123

资源命名的几个要点:

  • 使用复数名词/users 而非 /user,保持集合概念的一致性
  • 使用小写字母:避免大小写带来的歧义
  • 使用连字符分隔多单词/comic-scripts 而非 /comicScripts/comic_scripts
  • 不要在路径中放操作动词:HTTP 方法本身就是动词

HTTP 方法的语义

REST 将数据操作映射到标准 HTTP 方法上。每种方法有明确的语义约定,正确使用它们能让 API 的行为可预测。

HTTP 方法语义幂等性典型用途示例
GET读取资源✅ 幂等查询列表、获取详情GET /api/users/123
POST创建资源❌ 不幂等新增记录、提交表单POST /api/users
PUT全量替换✅ 幂等更新资源全部字段PUT /api/users/123
PATCH部分更新❌ 不幂等修改资源部分字段PATCH /api/users/123
DELETE删除资源✅ 幂等移除记录DELETE /api/users/123

幂等性(Idempotency)是理解 HTTP 方法的关键概念。一个操作执行一次和执行多次,结果相同,就是幂等的。GETPUTDELETE 天然幂等;POST 不幂等,因为每次调用都可能创建新资源。理解这一点,有助于你在设计 API 时做出合理的方法选择。

状态码的规范使用

HTTP 状态码是服务端对请求结果的「一句话回答」。很多开发者习惯返回 200 然后用 JSON 里的 code 字段表示错误,这种做法绕过了 HTTP 协议本身提供的语义体系。

常用的状态码分三类:

2xx 成功

状态码含义使用场景
200 OK请求成功GET、PUT、PATCH 的常规响应
201 Created资源已创建POST 创建成功后
204 No Content成功但无返回体DELETE 成功后

4xx 客户端错误

状态码含义使用场景
400 Bad Request请求参数有误校验失败、格式错误
401 Unauthorized未认证缺少或无效的 Token
403 Forbidden无权限已认证但权限不足
404 Not Found资源不存在查询的 ID 无效
409 Conflict资源冲突重复创建、版本冲突
422 Unprocessable Entity语义错误格式正确但业务校验失败
429 Too Many Requests请求频率超限触发限流策略

5xx 服务端错误

状态码含义使用场景
500 Internal Server Error服务器内部错误未捕获的异常
502 Bad Gateway网关错误上游服务不可用
503 Service Unavailable服务不可用维护或过载

一条实用原则:「不一致的状态码是客户端 Bug 最常见的来源之一。」如果你的 API 在删除成功时返回 200,有时返回 204,客户端就不得不为每个接口写特殊逻辑。保持一致,比追求「语义完美」更重要。

路由设计

路由是 API 的门面。好的路由设计让开发者「看一眼就知道怎么用」,坏的路由设计让人需要反复查阅文档。

命名规范

路由命名遵循几个基本原则:

# 基础结构
/{version}/{resource}
/{version}/{resource}/{id}
/{version}/{resource}/{id}/{sub-resource}

# 示例
/api/v1/users
/api/v1/users/abc123
/api/v1/users/abc123/orders

具体规范:

  • 路径全部小写/api/comic-scripts 而非 /api/ComicScripts
  • 使用复数/users 而非 /user,表示这是一个集合
  • 用连字符分隔/comic-scripts 而非 /comic_scripts/comicScripts
  • 层级不超过两层/users/123/orders 可以,/users/123/orders/456/items/789 太深了,考虑将深层资源提升为顶级资源
  • 避免在路径中暴露内部实现/api/v1/internal-db-query 不合适,/api/v1/search 更好

层级关系与嵌套

资源之间经常存在从属关系。例如用户拥有多个订单,订单包含多个商品。在路由中表达这种关系时,需要平衡「语义清晰」和「路径简洁」。

# ✅ 两层嵌套,清晰表达从属关系
GET /api/v1/users/{userId}/orders
GET /api/v1/users/{userId}/orders/{orderId}

# ❌ 三层以上嵌套,路径过长且脆弱
GET /api/v1/users/{userId}/orders/{orderId}/items/{itemId}/reviews

# ✅ 将深层资源提升为顶级,通过查询参数关联
GET /api/v1/reviews?orderId={orderId}&itemId={itemId}

一条经验法则:嵌套层级超过两层时,考虑是否需要将子资源提升为独立资源,通过查询参数或请求体来建立关联。

参数设计

API 中的参数主要有三种传递方式:

路径参数(Path Parameter)——定位具体资源

GET /api/v1/users/{userId}
# userId 是路径的一部分,不可缺少

查询参数(Query Parameter)——过滤、排序、分页

GET /api/v1/users?role=admin&sort=-createdAt&page=2&limit=20

查询参数的设计约定:

参数用途示例
sort排序字段,- 前缀表示降序sort=-createdAt
filter / 字段名条件过滤role=adminstatus=published
page / offset分页偏移page=2offset=40
limit / pageSize每页数量limit=20pageSize=20
q / search全文搜索q=AI漫画
fields字段选择(稀疏字段集)fields=id,name,email

请求体(Request Body)——复杂查询或创建数据

// POST /api/v1/comic-scripts
{
  "title": "AI 冒险之旅",
  "genre": "科幻",
  "panels": [
    { "scene": "太空站", "dialogue": "准备出发" }
  ]
}

请求与响应格式

统一的请求和响应格式,是 API 一致性的基础。团队内部可能同时开发多个模块,如果每个模块的响应结构不同,前端就需要为每个接口写不同的解析逻辑。

JSON 响应结构

推荐的标准响应结构:

成功响应

{
  "data": {
    "id": "usr_abc123",
    "name": "张三",
    "email": "[email protected]",
    "createdAt": "2026-06-15T08:30:00Z"
  }
}

列表响应(含分页)

{
  "data": [
    { "id": "usr_001", "name": "张三" },
    { "id": "usr_002", "name": "李四" }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 20,
    "total": 156,
    "totalPages": 8
  }
}

错误响应

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求参数校验失败",
    "details": [
      {
        "field": "email",
        "message": "邮箱格式不正确"
      },
      {
        "field": "age",
        "message": "年龄必须大于 0"
      }
    ],
    "requestId": "req_xyz789"
  }
}

这种结构有几个设计考量:

  • data 字段:将业务数据包裹在 data 中,与 errorpagination 等元信息分离,避免字段名冲突
  • error 对象:包含机器可读的 code 和人类可读的 messagedetails 数组支持多字段错误同时返回
  • requestId:方便问题排查,客户端可以将其提供给后端开发者定位日志

分页策略

分页是列表接口的标配,常见的分页方式有三种:

分页方式适用场景优点缺点
偏移分页(Offset)后台管理系统、数据量较小可跳页、实现简单数据变动时可能重复或遗漏
游标分页(Cursor)信息流、高频写入的数据集数据一致性好、性能稳定不支持跳页、实现较复杂
时间分页(Time-based)日志、审计记录天然有序、易于理解精度依赖时间戳

偏移分页的响应:

{
  "data": [...],
  "pagination": {
    "page": 2,
    "pageSize": 20,
    "total": 156,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": true
  }
}

游标分页的响应:

{
  "data": [...],
  "pagination": {
    "nextCursor": "eyJpZCI6MTAwfQ==",
    "hasNext": true
  }
}

Postman 的技术博客指出,对于动态或高频写入的数据集,「游标分页比偏移分页更可靠」。如果你的 AI 平台有实时生成的漫画列表,游标分页是更合适的选择。

字段命名约定

在整个 API 中保持统一的字段命名风格。最常见的约定是使用 camelCase(JavaScript 生态)或 snake_case(Python/Ruby 生态)。一旦选定,所有接口、所有字段保持一致。

// camelCase(JavaScript/TypeScript 生态常用)
{
  "createdAt": "2026-06-15T08:30:00Z",
  "comicScriptId": "cs_001",
  "panelCount": 12
}
 
// snake_case(Python/Ruby 生态常用)
{
  "created_at": "2026-06-15T08:30:00Z",
  "comic_script_id": "cs_001",
  "panel_count": 12
}

对于出海产品,推荐使用 camelCase,因为前端消费方大多使用 JavaScript/TypeScript,保持一致可以减少序列化层的转换成本。

时间格式

统一使用 ISO 8601 格式,带时区信息:

{
  "createdAt": "2026-06-15T08:30:00Z",
  "updatedAt": "2026-07-01T14:22:30+08:00"
}

避免使用时间戳(1719295800)作为 API 响应的时间格式,因为时间戳的可读性差,且不同语言对秒/毫秒的处理不一致。

版本管理策略

API 不是一成不变的。业务在发展,需求在变化,接口必然要迭代。版本管理的核心目标是:在不破坏现有客户端的前提下,安全地演进 API。

何时需要新版本

并非所有改动都需要新版本。判断标准是:这次改动是否是「破坏性变更」(Breaking Change)。

需要新版本的情况:

  • 删除或重命名已有字段
  • 修改字段的数据类型
  • 移除已有接口
  • 修改必填参数
  • 改变响应的核心结构

不需要新版本的情况:

  • 新增可选字段
  • 新增接口
  • 新增可选的查询参数
  • enum 中追加新值(前提是客户端能优雅处理未知值)

四种版本管理策略

策略示例优点缺点适用场景
URL 路径版本/api/v1/users直观易懂,所有 HTTP 客户端和工具原生支持URL 较长,URL 结构变化可能影响路由大多数场景的首选,Google、Stripe、GitHub 等主流 API 均采用
查询参数版本/api/users?version=1资源 URI 保持不变版本信息不直观,容易遗忘,默认版本管理复杂内部 API 或快速迭代阶段
请求头版本Accept-Version: v1灵活,不污染 URL,缓存友好调试时不可见,需要客户端额外配置追求 REST 纯粹性的团队
媒体类型版本Accept: application/vnd.myapp.v1+json符合 HTTP 内容协商规范实现复杂,客户端使用门槛高GitHub API 采用,适合大型开放平台

对于大多数团队,URL 路径版本/api/v1/)是务实的选择。它足够直观,文档和调试工具都原生支持,前端开发者也不需要额外配置。Google Cloud 的 API 设计指南和 Postman 的最佳实践指南都推荐这种方式作为默认方案。

版本迁移的实操建议

# 1. 新版本上线时,旧版本继续提供服务
/api/v1/users   ← 继续可用
/api/v2/users   ← 新版本

# 2. 在响应头中提醒客户端迁移
X-API-Deprecated: true
Sunset: Sat, 01 Mar 2027 00:00:00 GMT
Link: <https://docs.example.com/migration/v1-to-v2>; rel="migration-guide"

# 3. 设定明确的废弃时间表,提前 6-12 个月通知
# 4. 提供迁移指南文档

HTTP 的 Sunset 头(RFC 8594)是专门用于告知客户端某个接口将在何时下线的标准机制。善用这个头部,可以让版本迁移更加有序。

API 文档

没有文档的 API 等于没有 API。API 文档不仅是前端开发者的参考手册,也是后端团队自身的设计契约。

OpenAPI 规范

OpenAPI(前身是 Swagger)是目前最主流的 API 描述规范。它使用 YAML 或 JSON 格式定义接口的路径、参数、请求体、响应结构和错误码,可以自动生成文档、客户端 SDK 和服务端桩代码。

一个简化的 OpenAPI 片段:

openapi: 3.1.0
info:
  title: AI Comic Platform API
  version: 1.0.0
  description: AI 漫画平台后端 API
 
paths:
  /api/v1/comic-scripts:
    get:
      summary: 获取漫画剧本列表
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: 成功返回剧本列表
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ComicScript'
                  pagination:
                    $ref: '#/components/schemas/Pagination'

API 文档工具对比

工具类型特点适用场景
Swagger UI开源,自托管从 OpenAPI 规范自动生成可交互文档中小型团队,快速搭建
Redoc开源,自托管三栏布局,阅读体验好,支持大量接口接口数量多的中大型项目
Postman商业 + 免费层集合管理、Mock 服务、自动化测试一体化需要协作和测试的团队
Stoplight商业可视化设计 + 文档 + Mock,设计先行设计驱动的团队
Scalar开源现代化 UI,支持 OpenAPI 3.1,自动生成客户端代码追求现代开发者体验
Apifox商业 + 免费层中文友好,集 API 设计、调试、文档、Mock 于一体国内团队快速上手

对于出海产品,推荐组合:OpenAPI 规范 + Swagger UI 或 Redoc作为对外文档,Postman Collection 作为内部调试和协作工具。

API 设计流程

一个完整的 API 设计流程,从需求分析到文档交付,可以按以下步骤推进:

流程图画布 · 115%
Mermaid 流程图加载中...

关键节点说明:

  • 资源建模:梳理业务实体,确定哪些是资源、资源之间有什么关系
  • 路由设计:根据资源建模结果,规划 URI 结构和 HTTP 方法映射
  • 评审与对齐:前后端共同参与,确保双方对接口契约理解一致
  • 契约测试:基于 OpenAPI 规范自动生成测试用例,验证实现与文档一致

案例分析

案例一:AI 漫画剧本 API 设计

假设你正在为一个 AI 漫画平台设计后端 API。核心资源包括:用户(User)、漫画剧本(ComicScript)、分镜(Panel)。

资源建模

User        → /api/v1/users
ComicScript → /api/v1/comic-scripts
Panel       → /api/v1/comic-scripts/{scriptId}/panels

典型接口设计

# 获取剧本列表
GET /api/v1/comic-scripts?status=draft&sort=-createdAt&page=1&limit=20

# 创建剧本
POST /api/v1/comic-scripts
Body: { "title": "AI 冒险之旅", "genre": "sci-fi" }

# 获取剧本详情
GET /api/v1/comic-scripts/{scriptId}

# 更新剧本标题
PATCH /api/v1/comic-scripts/{scriptId}
Body: { "title": "AI 冒险之旅(修订版)" }

# 删除剧本
DELETE /api/v1/comic-scripts/{scriptId}

# 获取某剧本的分镜列表
GET /api/v1/comic-scripts/{scriptId}/panels?page=1&limit=50

# 为剧本新增分镜
POST /api/v1/comic-scripts/{scriptId}/panels
Body: { "scene": "太空站", "dialogue": "准备出发", "imageUrl": "..." }

错误处理示例

// POST /api/v1/comic-scripts,缺少必填字段
// HTTP 422 Unprocessable Entity
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求参数校验失败",
    "details": [
      { "field": "title", "message": "标题不能为空" },
      { "field": "genre", "message": "类型不在可选范围内" }
    ],
    "requestId": "req_abc456"
  }
}

这个案例体现了前文讨论的几个原则:资源用名词、方法用动词、分页用查询参数、错误用统一格式。

案例二:开放 API 的版本管理

假设你的 AI 平台要对外开放 API,供第三方开发者接入。版本管理策略的选择尤为关键。

初始设计(v1)

GET /api/v1/generate
POST /api/v1/generate
Body: { "prompt": "...", "style": "manga" }
Response: { "data": { "imageUrl": "https://..." } }

需求变更(v2)

产品迭代后,生成接口需要支持多张图片输出和风格组合:

POST /api/v2/generate
Body: {
  "prompt": "...",
  "styles": ["manga", "watercolor"],
  "imageCount": 4
}
Response: {
  "data": {
    "images": [
      { "url": "https://...", "style": "manga" },
      { "url": "https://...", "style": "watercolor" }
    ],
    "creditsUsed": 8
  }
}

版本共存策略

# v1 继续可用,但在响应头中标记废弃
HTTP/1.1 200 OK
X-API-Deprecated: true
Sunset: Sat, 01 Mar 2027 00:00:00 GMT

# v2 是当前推荐版本
# 在文档和开发者门户中,引导用户迁移到 v2

这个案例展示了版本管理的实际运作:新版本不是「替换」旧版本,而是「并行」提供,给客户端充足的迁移时间。

API 设计检查清单

在设计或评审 API 时,可以逐项检查以下清单:

  • 资源命名使用复数名词:路径用 /users 而非 /user
  • HTTP 方法语义正确:GET 查询、POST 创建、PUT 全量更新、PATCH 部分更新、DELETE 删除
  • 状态码使用规范:成功用 2xx、客户端错误用 4xx、服务端错误用 5xx,不使用 200 + error code
  • 响应格式统一:成功用 &#123; data: ... &#125;,错误用 &#123; error: &#123; code, message, details &#125; &#125;
  • 分页参数一致:所有列表接口使用相同的分页约定(page/limitcursor/limit
  • 错误信息包含 requestId:便于前后端协作排查问题
  • 字段命名风格一致:全部使用 camelCase 或 snake_case,不混用
  • 时间格式统一:使用 ISO 8601 格式(2026-07-01T08:30:00Z
  • 版本策略明确:使用 URL 路径版本(/v1/)并文档化
  • 破坏性变更触发新版本:新增字段不需要新版本,删除字段需要
  • OpenAPI 规范与实现同步:文档反映真实接口,而非反过来
  • 接口设计经过评审:前后端共同参与,避免「后端觉得合理但前端用不了」的情况
  • 废弃接口有 Sunset 计划:明确下线时间,提供迁移指南

小结

API 设计不是一次性工作,而是一个持续演进的过程。好的 API 设计让前后端合作更顺畅,让第三方集成更简单,让系统维护更轻松。

核心原则并不复杂:资源用名词、方法用动词、状态码用标准、响应格式要统一、版本管理要透明、文档要实时。难的是在团队规模扩大、业务复杂度增加的过程中,持续遵守这些原则。

对于出海产品,API 还是你的产品面向全球开发者的「门面」。一套规范的 API 设计,传递的是专业性和可靠性。

参考资料

  1. Best practices for RESTful web API design — Microsoft Learn
  2. REST API Best Practices: A Developer's Guide — Postman Blog
  3. Best Practices in API Design — Swagger
  4. API Design Guide — Google Cloud Documentation
  5. API Versioning Best Practices — Gravitee
  6. RESTful API 设计指南:从核心原则到规范实践 — 稀土掘金
  7. REST API 设计规范:最佳实践和示例 — Apifox
  8. API Design Best Practices Guide — Fern