API 入门与设计
原始素材:
4-服务器与后端/4.08-api-intro.md
什么是 API? 这就像问:餐厅的菜单怎么设计,客人一看就懂?服务员怎么记单,不会出错?API 解决的就是"程序之间如何对话"的问题。你写代码的第一天就在用 API,只是你可能没意识到。
0. 新手常见的三个困惑
困惑一:API 是很高深的东西吗?
很多人一听到 API,就觉得是高级工程师才能理解的概念。其实你早就用过 API 了:
len("hello") # 这就是 Python 提供的 API
open("file.txt") # 这也是 API
requests.get(url) # 这还是 API
困惑二:Web API 和普通 API 有什么区别?
| 类型 | 调用对象 | 通信方式 | 典型场景 |
|---|---|---|---|
| 函数 API | 本地代码 | 函数调用 | len(), open() |
| 操作系统 API | 操作系统 | 系统调用 | 读写文件、创建进程 |
| Web API | 远程服务器 | HTTP 请求 | 调用 AI 模型、获取天气 |
困惑三:我该用 HTTP 还是 SDK?
import requests
response = requests.post(
"https://api.deepseek.com/v1/chat/completions",
headers={"Authorization": "Bearer sk-xxx"},
json={"model": "deepseek-chat", "messages": [...]}
)
result = response.json()["choices"][0]["message"]["content"]
from openai import OpenAI
client = OpenAI(api_key="sk-xxx")
response = client.chat.completions.create(
model="deepseek-chat",
messages=[...]
)
result = response.choices[0].message.content
1. API 的本质:插头与插座
API(Application Programming Interface,应用程序编程接口)就是"程序之间对话的约定"。
1.1 用电器来类比
| 概念 | 电器类比 | API 对应 |
|---|---|---|
| 接口 | 插座形状 | 函数签名 / URL |
| 输入 | 电流输入 | 函数参数 / 请求体 |
| 输出 | 电器工作 | 返回值 / 响应体 |
1.2 三种 API 形态对比
调用对象本地代码库
通信方式函数调用
延迟纳秒级
典型场景数据处理、文件操作
函数 API 示例
len("hello") # 返回 5
max([1, 5, 3]) # 返回 5
open("file.txt").read() # 读取文件
1.3 函数 API vs HTTP API 的区别
很多初学者会困惑:函数 API 和 HTTP API 到底有什么区别?看文档时该如何区分?
| 维度 | 函数 API(本地) | HTTP API(远程) |
|---|---|---|
| 调用方式 | 直接函数调用 | 网络请求 |
| 参数传递 | 括号内传参 | URL / Body / Header |
| 返回值 | 直接获得结果 | JSON / XML 响应 |
| 错误处理 | 异常 / 返回值 | HTTP 状态码判断 |
函数 API 示例:
# 调用内置函数
length = len("hello") # 返回 5
# 调用库函数
import math
result = math.sqrt(16) # 返回 4.0
# 调用自定义函数
def add(a, b):
return a + b
sum = add(3, 5) # 返回 8
HTTP API 示例:
POST /v1/chat/completions HTTP/1.1
Host: api.deepseek.com
Authorization: Bearer sk-xxx
Content-Type: application/json
{"model": "deepseek-chat", "messages": [{"role": "user", "content": "你好"}]}
核心要点: 函数 API 是"本地办事",HTTP API 是"远程通信"。看文档时,函数关注参数和返回值,HTTP API 关注 Endpoint、认证和请求/响应格式。
1.4 不同类型的 API 文档怎么看
面对不同类型的 API 文档,关注重点各不相同:
| 维度 | 函数文档 | REST API 文档 | SDK 文档 |
|---|---|---|---|
| 适用场景 | 使用标准库/第三方库函数 | 调用远程服务 | 使用厂商 SDK |
| 阅读难度 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| 核心关注 | 参数、返回值 | Endpoint、请求体 | 初始化、方法链 |
| 代码示例 | 函数调用 | HTTP 请求 | 对象方法 |
| 错误处理 | 异常/返回值 | 状态码 | 异常对象 |
| 先看什么 | 函数签名 | Base URL + Auth | Quick Start |
函数文档示例
### json.loads(s, *, cls=None, object_hook=None...)
将 JSON 字符串解析为 Python 对象
**参数:**
- s (str): 要解析的 JSON 字符串
- cls (JSONDecoder): 自定义解码器类
- object_hook (callable): 可选的转换函数
**返回值:**
- dict | list: 解析后的 Python 对象
**异常:**
- JSONDecodeError: 字符串格式非法
**示例:**
>>> import json
>>> json.loads('{"name": "Alice"}')
{'name': 'Alice'}
阅读建议
- 先看函数签名,了解需要什么参数
- 注意参数的类型和是否必填
- 查看返回值类型,方便后续处理
- 关注可能抛出的异常,做好错误处理
阅读建议 :函数文档看签名,API 文档看请求格式,SDK 文档看示例。遇到不会的,先找「Quick Start」或「Getting Started」章节。
2. 一次完整的 API 调用
API 调用演示:选择端点 GET /api/users | POST /api/users | GET /api/users/999 | POST /api/orders → HTTP Request → 等待中... → HTTP Response ←
2.1 API 调用的四个阶段
| 阶段 | 发生了什么 | 电器类比 |
|---|---|---|
| 请求 | 客户端向服务器发送请求 | 按下开关 |
| 传输 | 请求通过网络传输到服务器 | 电流通过电线 |
| 处理 | 服务器处理请求并返回数据 | 电器开始工作 |
| 响应 | 客户端接收并处理返回结果 | 灯泡发光 |
2.2 餐厅类比
| 餐厅角色 | API 对应 | 说明 |
|---|---|---|
| 菜单 | API 文档 | 告诉你有哪些"菜"可以点 |
| 服务员 | HTTP 协议 | 标准化的"对话方式" |
| 后厨 | 服务端 | 按"订单"处理请求 |
| 上菜 | 响应 | 把结果返回给"客人" |
3. HTTP 方法:你是在"问"还是在"做"?
调用 Web API 时,你需要告诉服务器你想做什么。这就是 HTTP 方法的由来。
3.1 用餐厅点餐来理解
| 场景 | 现实中你会怎么说? | 对应的 HTTP 方法 |
|---|---|---|
| 你想知道今天有什么菜 | "服务员,菜单给我看看" | GET - 纯"问",不改数据 |
| 你想点一份宫保鸡丁 | "给我来份宫保鸡丁" | POST - "做"件事,创建数据 |
| 你想换一道菜 | "把宫保鸡丁改成糖醋里脊" | PUT - 替换数据 |
| 你想改口味 | "宫保鸡丁不要放花生" | PATCH - 部分修改 |
| 你不想要了 | "算了,那道菜不要了" | DELETE - 删除数据 |
关于幂等性
幂等性 :多次执行结果是否相同?
- 幂等的操作(GET/PUT/DELETE):点 10 次和点 1 次,结果一样
- 不幂等的操作(POST):点 10 次,可能创建 10 个订单
解决方案 :POST 操作用唯一 ID 校验,避免重复处理。
3.2 HTTP 方法速查表
| 方法 | 用途 | 幂等性 | 安全性 | 典型场景 |
|---|---|---|---|---|
| POST | 创建资源 | 否 | 否 | 新增用户、提交订单 |
| PUT | 全量更新 | 是 | 否 | 替换整个用户资料 |
| PATCH | 部分更新 | 否 | 否 | 只修改昵称 |
| DELETE | 删除资源 | 是 | 否 | 删除用户、取消订单 |
4. HTTP 状态码:服务器在告诉你什么?
服务器回复时,会先返回一个状态码,告诉你请求是否成功。
4.1 状态码分类
| 分类 | 含义 | 典型状态码 |
|---|---|---|
| 2xx | 成功 - 请求被成功接收、理解并处理 | 200 OK, 201 Created, 204 No Content |
| 3xx | 重定向 - 需要进一步操作才能完成请求 | 301 永久移动, 304 未修改, 307 临时重定向 |
| 4xx | 客户端错误 - 请求包含错误或无法完成 | 400 参数错误, 401 未认证, 403 无权限, 404 不存在 |
| 5xx | 服务器错误 - 服务器无法处理有效请求 | 500 内部错误, 502 网关错误, 503 服务不可用 |
4.2 常见状态码详解
| 状态码 | 含义 | 典型场景 | 客户端处理 |
|---|---|---|---|
| 200 OK | 成功 | 请求正常处理 | 展示数据 |
| 201 Created | 创建成功 | POST 请求成功创建资源 | 跳转到新资源 |
| 400 Bad Request | 请求格式错误 | 参数缺失或格式不对 | 检查参数 |
| 401 Unauthorized | 未认证 | 没有提供有效的 API Key | 引导用户登录 |
| 403 Forbidden | 无权限 | API Key 没有访问该资源的权限 | 提示权限不足 |
| 404 Not Found | 不存在 | 请求的地址或资源不存在 | 检查 URL |
| 429 Too Many Requests | 请求过多 | 超过了速率限制 | 稍后重试 |
| 500 Internal Server Error | 服务器错误 | 服务端出了问题 | 提示用户稍后重试 |
快速参考表
| 分类 | 状态码 | 含义 |
|---|---|---|
| ✅ 成功 | 200 | OK - 请求成功 |
| 201 | Created - 创建成功 | |
| 204 | No Content - 无返回内容 | |
| ⚠️ 客户端错误 | 400 | Bad Request - 请求格式错误 |
| 401 | Unauthorized - 未认证 | |
| 403 | Forbidden - 无权限 | |
| 404 | Not Found - 资源不存在 | |
| 422 | Unprocessable - 语义错误 | |
| 429 | Too Many - 请求过多 | |
| ❌ 服务器错误 | 500 | Server Error - 内部错误 |
| 502 | Bad Gateway - 网关错误 | |
| 503 | Unavailable - 服务不可用 |
5. HTTP vs SDK:自己跑腿还是让管家代办?
5.1 两种调用方式对比
| 维度 | 🏃 HTTP API(直接请求) | 🤵 SDK(封装调用) |
|---|---|---|
| 比喻 | 自己跑腿 | 管家代办 |
| 优点 | ✓ 所有语言都能用 / ✓ 完全控制请求细节 / ✓ 无需额外依赖 | ✓ 代码简洁易读 / ✓ 自动处理鉴权 / ✓ 内置错误重试 |
| 缺点 | ✗ 需要处理所有细节 / ✗ 代码冗长易出错 | ✗ 需要安装依赖 / ✗ 可能有版本问题 |
| 代码示例 | requests.post(url, json=..., headers={...}) |
client.chat.completions.create(...) |
5.2 如何选择?
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 快速开发 | SDK | 自动处理鉴权、错误、重试 |
| 学习原理 | HTTP | 理解底层机制 |
| 不支持的语言 | HTTP | 任何语言都能用 |
| 需要定制 | HTTP | 灵活控制每个细节 |
能用 SDK 就用 SDK ,把麻烦事留给库,把时间留给自己。
6. 如何阅读 API 文档?
API 文档就像说明书和菜单的结合体。你不需要从头读到尾,只需要学会"查字典"。
6.1 文档阅读清单
打开任何一个 API 文档(如 OpenAI 或 DeepSeek),你只需要找这几样东西:
| 要素 | 值 | 说明 |
|---|---|---|
| Base URL | https://api.deepseek.com |
API 服务地址 |
| Endpoint | POST /v1/chat/completions |
接口路径 + 方法 |
| Headers | Authorization: Bearer sk-xxx / Content-Type: application/json |
鉴权 + 内容类型 |
| Body 参数 | model(必填)、messages(必填)、temperature(可选,0-2,默认 1) |
请求体字段 |
翻译成代码:
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://api.deepseek.com"
)
response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": "你好"}]
)
核心思想: 看文档找三样:地址(Base URL)、鉴权(Authorization)、参数(Parameters)。
| 项目 | 说明 | 示例 |
|---|---|---|
| Base URL | API 的根地址 | https://api.deepseek.com |
| Authentication | 如何证明身份 | Authorization: Bearer sk-xxx |
| Endpoints | 具体的接口列表 | /v1/chat/completions |
| Parameters | 必填/可选参数 | model(必填)、temperature(可选) |
| Response | 返回数据结构 | {"choices": [...]} |
6.2 阅读文档的步骤
- 找到 Base URL - 这是所有请求的前缀
- 看懂认证方式 - API Key 放在 Header 还是 Query?
- 找到需要的 Endpoint - 你要调用的具体接口
- 查看请求参数 - 哪些必填?哪些可选?
- 理解返回格式 - 数据是如何组织的?
Endpoint
方法
GETPOSTPUTDELETE
API Key
试着触发以下场景:
- ✅ 成功请求 :填入正确的 Endpoint 和 API Key
- ❌ 404 错误 :填一个不存在的地址
8. 小结
核心要点
- API 就是传声筒 ,帮你把话传给另一段代码或远程服务器
- 你早就用过 API 了 ,从
len()到open()都是 API - Web API 是超能力 ,让你调用千里之外的超级电脑
- SDK 是好管家 ,能用 SDK 就别自己跑腿
- 看文档找三样 :地址、鉴权、参数
在 AI 编程的时代,你只需要记住这几个核心概念。剩下的细节,IDE 和 AI 助手会帮你处理。
名词速查表
| 名词 | 全称 | 解释 |
|---|---|---|
| API | Application Programming Interface | 应用程序编程接口,定义了软件之间如何交互 |
| Web API | - | 基于 HTTP 协议的 API,用于网络通信 |
| Endpoint | - | 端点,API 的具体地址 |
| HTTP | HyperText Transfer Protocol | Web API 使用的通信协议 |
| GET | - | 获取资源的方法 |
| POST | - | 提交数据的方法 |
| SDK | Software Development Kit | 软件开发工具包,封装了底层 API 调用 |
| URL | Uniform Resource Locator | API 的网络地址 |
| JSON | JavaScript Object Notation | 常用的数据格式 |
| Authentication | - | 验证身份的过程 |
| Status Code | - | HTTP 响应中的状态码 |
| Request | - | 请求 |
| Response | - | 响应 |
| Header | - | HTTP 头,包含元信息 |
| Payload | - | 请求或响应的实际数据 |
| Rate Limit | - | 速率限制 |
| Idempotent | - | 幂等,多次执行结果相同 |
| REST | Representational State Transfer | 一种 API 架构风格 |
| RPC | Remote Procedure Call | 远程过程调用 |
| GraphQL | - | 一种查询语言 API |
| gRPC | - | Google 开发的高性能 RPC 框架 |
原始素材:
4-服务器与后端/4.07-api-design.md
前后端如何高效对话? 这就像问:餐厅的菜单怎么设计,客人一看就懂?服务员怎么记单,不会出错?上菜怎么规范,客人满意?API 设计解决的就是"对话规则"的问题。
0. 先问一个问题:你有没有经历过这些噩梦?
场景一:接口命名随心所欲
GET /getUserData
GET /fetchUserInfo
GET /queryUserById
GET /users/query
四个接口,功能一样,命名风格完全不同。新人入职一脸懵:我该用哪个?
场景二:错误处理五花八门
// 有的返回 HTTP 状态码
HTTP/1.1 404 Not Found
// 有的返回 200 + code
HTTP/1.1 200 OK
{ "code": 404, "message": "用户不存在" }
// 有的直接抛异常
HTTP/1.1 200 OK
{ "error": "出错了" }
前端不知道该怎么判断请求是否成功。
场景三:响应结构千人千面
// 接口 A
{ "data": { ... } }
// 接口 B
{ "result": { ... } }
// 接口 C
{ "content": { ... } }
每个接口返回格式都不一样,前端需要针对每个接口单独处理。
好的 API 设计就像餐厅的点餐系统 ——菜单清晰、流程规范、出错有提示。
1. 什么是 API?
API (Application Programming Interface,应用程序编程接口)就是"程序之间对话的约定"。
1.1 用餐厅来类比
| 餐厅角色 | 对应概念 | 说明 |
|---|---|---|
| 菜单 | API 文档 | 告诉你有哪些"菜"可以点 |
| 服务员 | HTTP 协议 | 标准化的"对话方式" |
| 后厨 | 服务端 | 按"订单"处理请求 |
| 上菜 | 响应 | 把结果返回给"客人" |
1.2 一个完整的 API 请求
API 调用演示:选择端点 GET /api/users | POST /api/users | GET /api/users/999 | POST /api/orders → HTTP Request → 等待中... → HTTP Response ←
2. API 设计哲学:RPC / REST / GraphQL / gRPC
在开始具体的 RESTful 设计之前,先了解四种主流的 API 设计风格:
REST
最常用
Representational State Transfer,表述性状态转移。由 Roy Fielding 于 2000 年在其博士论文中提出。面向资源,用 URL 标识资源,用 HTTP 方法操作资源。
示例:获取用户信息
GET /users # 获取用户列表
GET /users/123 # 获取单个用户
POST /users # 创建用户
PUT /users/123 # 全量更新
PATCH /users/123 # 部分更新
DELETE /users/123 # 删除用户
核心特点
✓URL 是名词,不是动词
✓使用 HTTP 方法表达操作
✓无状态,请求包含所有信息
✓可缓存,支持分层系统
适用场景公开 API、CRUD 操作、资源边界清晰的业务
| 特性 | RPC | REST | GraphQL | gRPC |
|---|---|---|---|---|
| 核心理念 | 面向过程 | 面向资源 | 面向数据 | 面向方法 |
| URL 风格 | 动词为主 | 名词为主 | 单一端点 | 不依赖URL |
| 学习曲线 | 低 | 中 | 中 | 高 |
| 性能 | 一般 | 一般 | 较好 | 优秀 |
| 使用占比 | ~30% | ~50% | ~15% | ~5% |
2.1 REST vs RESTful:有什么区别?
很多人会混淆这两个概念:
| 概念 | 含义 | 说明 |
|---|---|---|
| REST | 一种架构风格 | 由 Roy Fielding 提出的设计理念,包含一组约束条件 |
| RESTful | 符合 REST 风格的 | 形容词,表示 API 设计遵循了 REST 原则 |
类比 :
- REST 就像"极简主义"——一种设计理念
- RESTful API 就像"极简风格的房间"——应用了这个理念的具体实现
REST 的六大约束 :
| 约束 | 说明 |
|---|---|
| 客户端-服务器分离 | 前后端独立开发,接口解耦 |
| 无状态 | 每个请求包含所有必要信息,服务器不保存会话状态 |
| 可缓存 | 响应应标明是否可缓存,提高性能 |
| 统一接口 | 使用标准的 HTTP 方法和状态码 |
| 分层系统 | 客户端无需知道连接的是哪层服务器 |
| 按需代码 (可选) | 服务器可以扩展客户端功能 |
- 学习成本低 :HTTP 协议本身就体现了 REST 思想
- 生态成熟 :工具、框架、文档丰富
- 通用性强 :任何语言、任何平台都能调用
- 易于缓存 :GET 请求天然可缓存,CDN 友好
3. RESTful 设计:让 URL 会说话
REST (Representational State Transfer)是一种架构风格,核心思想是:
- 把网络上的事物抽象为"资源"(Resource)
- 用 URL 标识资源
- 用 HTTP 方法操作资源
3.1 用仓库来类比
| 仓库概念 | REST 对应 | 示例 |
|---|---|---|
| 货架地址 | URL | /users、/orders |
| 操作方式 | HTTP 方法 | GET(查看)、POST(入库) |
| 货物 | 资源 | 用户数据、订单数据 |
关键原则 :URL 是名词,不是动词。
3.2 URL 设计规则
| 规则 | 错误示例 | 正确示例 | 说明 |
|---|---|---|---|
| 用名词不用动词 | /getUsers |
/users |
URL 表示资源,HTTP 方法表示操作 |
| 用复数形式 | /user |
/users |
统一复数风格 |
| 小写+连字符 | /UserProfiles |
/user-profiles |
URL 大小写敏感 |
| 避免层级过深 | /a/b/c/d/e |
/a/b/c |
最多 3 层 |
| 过滤用查询参数 | /products/phone/5000 |
/products?cat=phone |
过滤条件用 ? 参数 |
统一用小写 + 连字符(-)是最安全的做法,避免大小写混乱和下划线风格不一致的问题。
3.3 HTTP 方法选择
| 方法 | 用途 | 幂等性 | 安全性 | 典型场景 |
|---|---|---|---|---|
| POST | 创建资源 | 否 | 否 | 新增用户、提交订单 |
| PUT | 全量更新 | 是 | 否 | 替换整个用户资料 |
| PATCH | 部分更新 | 否 | 否 | 只修改昵称 |
| DELETE | 删除资源 | 是 | 否 | 删除用户、取消订单 |
幂等性 :多次执行结果相同。
- 幂等的操作 (GET/PUT/DELETE):点 10 次和点 1 次,结果一样
- 不幂等的操作 (POST):点 10 次,可能创建 10 个订单
解决方案 :POST 操作用唯一 ID 校验,避免重复处理。
4. 状态码:让错误"会说话"
HTTP 状态码是服务器告诉客户端"发生了什么"的标准方式。
4.1 状态码分类
| 分类 | 含义 | 典型状态码 |
|---|---|---|
| 2xx | 成功 | 200 OK、201 Created、204 No Content |
| 3xx | 重定向 | 301 永久移动、304 未修改 |
| 4xx | 客户端错误 | 400 参数错误、401 未认证、404 不存在 |
| 5xx | 服务端错误 | 500 内部错误、503 服务不可用 |
✅ 2xx 成功
| 状态码 | 含义 | 说明 |
|---|---|---|
| 200 | OK | 请求成功 |
| 201 | Created | 创建成功 |
| 204 | No Content | 成功但无返回内容 |
⚠️ 4xx 客户端错误
| 状态码 | 含义 | 说明 |
|---|---|---|
| 400 | Bad Request | 请求格式错误 |
| 401 | Unauthorized | 未认证 |
| 403 | Forbidden | 无权限 |
| 404 | Not Found | 资源不存在 |
| 422 | Unprocessable | 语义错误 |
| 429 | Too Many | 请求过多 |
❌ 5xx 服务器错误
| 状态码 | 含义 | 说明 |
|---|---|---|
| 500 | Server Error | 服务器内部错误 |
| 502 | Bad Gateway | 网关错误 |
| 503 | Unavailable | 服务不可用 |
5. 错误处理:优雅地"拒绝"
好的错误处理能让客户端"看状态码就知道怎么回事",而不是去猜。
4.1 错误处理的"避坑指南"
坑 1:所有错误都返回 200
// ❌ 错误做法
HTTP/1.1 200 OK
{ "error": "出错了" }
问题:缓存层会缓存这个"成功"响应,监控系统发现不了问题。
坑 2:错误信息太笼统
// ❌ 错误做法
HTTP/1.1 400 Bad Request
{ "message": "参数错误" }
问题:客户端不知道哪个参数错了、为什么错。
坑 3:暴露敏感信息
// ❌ 危险做法
HTTP/1.1 500 Internal Server Error
{ "stack": "at UserService.login...", "sql": "SELECT * FROM..." }
危险:暴露了代码结构、数据库查询,攻击者可以利用这些信息。
// 对比好的和差的错误处理方式
❌ 差: 所有错误都 200``❌ 差: 错误信息太笼统``❌ 差: 暴露敏感信息``✅ 好: 正确的状态码``✅ 好: 详细的错误信息``✅ 好: 安全的错误响应
响应结构
6. 版本控制:API 的"向后兼容"
6.1 为什么要版本控制?
场景:你的 App 有 100 万用户,需要修改订单接口。
如果不做版本控制 :
- 新 App 调用新接口 → 正常
- 旧 App 调用新接口 → 字段缺失,崩溃!
正确的做法 :
/v1/orders- 旧接口,继续服务旧 App/v2/orders- 新接口,新功能在这里
6.2 版本控制策略
| 策略 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| URL 路径 | /v1/users |
直观、易缓存 | URL 变长 |
| 请求头 | Accept: vnd.api.v2+json |
URL 干净 | 不便调试 |
| 查询参数 | /users?version=2 |
简单 | 不够标准 |
6.3 版本演进示例
以用户接口为例,展示 v1 到 v2 的演进:
| 接口 | v1(旧版) | v2(新版) | 变化说明 |
|---|---|---|---|
| 获取用户 | GET /v1/users |
||
返回:name, email |
GET /v2/users |
||
返回:name, email, avatar, phone |
新增头像、手机号字段 | ||
| 创建订单 | POST /v1/orders |
||
接收:items[] |
POST /v2/orders |
||
接收:items[], coupons[] |
新增优惠券支持 | ||
| 批量操作 | 无 | POST /v2/orders/batch |
新增批量创建接口 |
- 保持向后兼容 :v1 接口至少维护 6-12 个月,给客户端升级时间
- 文档同步更新 :每个版本有独立的 API 文档
- 废弃公告 :提前通知 v1 将在何时下线,引导迁移
- 监控使用情况 :统计 v1 调用量,确认可以安全下线后再停止服务
7. 响应结构设计
响应结构是前后端协作的"数据契约",统一格式能大幅降低沟通成本。
❓ 为什么统一📝 字段说明🔢 状态码📄 示例📑 分页
为什么要统一响应格式?
❌ 问题:不同接口返回格式不一致
// 接口 A
{ "data": { "user": {...} } }
// 接口 B
{ "result": { "user": {...} } }
// 接口 C
{ "user": {...} }
前端需要针对每个接口单独处理,代码冗余,容易出错
✅ 解决:统一响应格式
{
"code": 0,
"message": "success",
"data": { ... },
"request_id": "req-xxx"
}
7.1 大厂实践参考
Google API 设计指南
参考 Google API Design Guide,Google 要求所有 API 错误响应必须包含 google.rpc.Status 消息结构:
{
"error": {
"code": 429,
"message": "资源不足,请稍后重试",
"status": "RESOURCE_EXHAUSTED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "RESOURCE_AVAILABILITY",
"domain": "compute.googleapis.com",
"metadata": {
"zone": "us-east1-a",
"service": "compute"
}
}
]
}
}
核心要求 :
- 必须包含
ErrorInfo提供机器可读的错误标识 message面向开发者,用简洁语言描述问题和解决方案details数组可包含LocalizedMessage(本地化消息)、Help(帮助链接)等
Microsoft REST API 指南
参考 Microsoft REST API Guidelines,微软强调响应的一致性:
错误与故障的分类 :
- 错误(Error) :客户端传递无效数据导致,返回 4xx,不影响 API 可用性
- 故障(Fault) :服务端无法正确响应有效请求,返回 5xx,影响 API 可用性
响应标头规范 :
Date:必须返回,使用 RFC 5322 格式(GMT 时区)Content-Type:必须返回ETag:支持乐观并发控制的资源必须返回
阿里巴巴 Java 开发手册
参考 阿里巴巴 Java 开发手册,阿里对 API 响应有以下规范:
统一返回对象 :
public class Result<T> {
private Integer code;
private String message;
private T data;
private String requestId;
}
错误码分段设计 :
| 范围 | 类型 | 示例 |
|---|---|---|
| 0 | 成功 | 0 |
| 1xxxx | 参数错误 | 10001 缺少必填参数 |
| 2xxxx | 业务错误 | 20001 余额不足 |
| 3xxxx | 认证错误 | 30001 未登录 |
| 5xxxx | 系统错误 | 50001 数据库异常 |
| Stripe API 响应设计 |
参考 Stripe API Documentation,Stripe 的错误响应设计非常精细:
{
"error": {
"type": "card_error",
"code": "card_declined",
"message": "Your card was declined.",
"param": "number",
"decline_code": "insufficient_funds",
"doc_url": "https://stripe.com/docs/error-codes/card-declined"
}
}
设计亮点 :
type区分错误类型:api_error、card_error、invalid_request_errorparam指出具体哪个参数出错,前端可直接定位表单字段doc_url提供文档链接,开发者可深入了解decline_code提供更细粒度的错误原因
JSON:API 规范
参考 JSON:API Specification,这是一个业界广泛采纳的 JSON API 响应规范:
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON:API 规范详解"
},
"relationships": {
"author": {
"data": { "type": "users", "id": "9" }
}
}
},
"included": [
{
"type": "users",
"id": "9",
"attributes": {
"name": "张三"
}
}
]
}
核心设计 :
data包含主资源,必须有type和idattributes存放资源属性relationships描述资源关联included避免重复请求,一次性返回关联数据
GitHub REST API 响应设计
参考 GitHub REST API Documentation,GitHub 的响应设计注重开发者体验:
成功响应 :
{
"id": 1296269,
"node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5",
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"owner": {
"login": "octocat",
"id": 1,
"avatar_url": "https://github.com/images/error/octocat_happy.gif"
},
"private": false,
"html_url": "https://github.com/octocat/Hello-World"
}
错误响应 :
{
"message": "Bad credentials",
"documentation_url": "https://docs.github.com/rest"
}
设计亮点 :
- 响应包含多种 URL 格式(
html_url、url)方便不同场景使用 - 错误响应包含
documentation_url指向文档 - 使用
Link响应头实现分页导航
Twitter/X API v2 响应设计
参考 Twitter API v2 Documentation,Twitter API v2 采用简洁的响应格式:
{
"data": {
"id": "1460323737035677698",
"text": "Hello, Twitter!"
},
"includes": {
"users": [
{
"id": "2244994945",
"name": "Twitter Dev",
"username": "TwitterDev"
}
]
}
}
设计亮点 :
data包含主数据,includes包含关联数据(类似 JSON:API)- 支持字段选择:
?tweet.fields=created_at,public_metrics - 分页使用
next_token和previous_token
7.2 最佳实践总结
综合以上规范,响应结构设计应遵循以下原则:
- 一致性优先 :所有接口使用相同的响应结构,前端可统一封装请求层
- 机器可读 :错误码 + 错误原因(reason)让程序能自动处理
- 人类友好 :message 描述清晰,包含解决建议
- 可追踪 :request_id 贯穿请求全链路,便于问题定位
- 国际化支持 :通过 details 扩展本地化消息
7.3 data 字段设计规范
data 是响应的核心,其设计直接影响前端开发效率。
单对象 vs 列表
单对象
{
"code": 0,
"data": {
"id": 123,
"name": "张三"
}
}
列表
{
"code": 0,
"data": {
"items": [...],
"pagination": {
"page": 1,
"total": 100
}
}
}
列表数据包裹在 items 数组中,分页信息放在 pagination 对象
7.4 错误响应设计进阶
⚠️错误响应设计进阶
参数校验错误
{
"code": 10001,
"message": "参数校验失败",
"data": {
"errors": [
{
"field": "email",
"message": "邮箱格式不正确",
"value": "invalid-email"
},
{
"field": "password",
"message": "密码长度至少 8 位",
"value": "123"
}
]
}
}
field出错字段名,前端可定位表单
message用户友好的错误描述
value客户端提交的值(可选)
参考链接
- Google API Design Guide - Errors
- Microsoft REST API Guidelines
- 阿里巴巴 Java 开发手册
- Heroku HTTP API Design Guide
- Stripe API - Errors
- JSON:API Specification
8. 实战:电商系统 API 设计示例
# 用户模块
GET /v1/users # 获取用户列表
POST /v1/users # 创建新用户
GET /v1/users/{id} # 获取用户详情
PUT /v1/users/{id} # 全量更新用户
PATCH /v1/users/{id} # 部分更新用户
DELETE /v1/users/{id} # 删除用户
# 订单模块
GET /v1/users/{id}/orders # 获取某用户的订单
POST /v1/orders # 创建订单
GET /v1/orders/{id} # 获取订单详情
PATCH /v1/orders/{id}/status # 更新订单状态
# 商品模块(复杂过滤用查询参数)
GET /v1/products?category=phone&price_max=5000&sort=price_desc&page=1
9. 用 AI 辅助设计 API
AI 可以帮助你快速生成符合规范的 API 设计。关键在于提供清晰的上下文和约束条件。
9.1 提示词模板
你是一位资深的后端架构师,精通 RESTful API 设计。请帮我设计一套 API 接口。
## 业务背景
[描述你的业务场景,例如:电商系统、博客平台、任务管理等]
## 功能需求
[列出需要的功能模块,例如:
- 用户管理:注册、登录、个人信息
- 订单管理:创建订单、查询订单、取消订单
- 商品管理:商品列表、商品详情、搜索]
## 设计要求
1. 遵循 RESTful 规范
2. URL 使用名词复数,小写+连字符
3. 正确使用 HTTP 方法(GET/POST/PUT/PATCH/DELETE)
4. 统一的响应格式:{ code, message, data, request_id }
5. 合理的状态码使用
6. 版本控制:URL 路径方式(/v1/)
## 输出格式
请按以下格式输出:
### 接口列表
| 方法 | URL | 描述 | 请求体 | 响应体 |
|------|-----|------|--------|--------|
### 请求/响应示例
[关键接口的详细示例]
### 状态码说明
[使用的状态码及其含义]
9.2 实战示例:电商订单 API
输入提示词:
你是一位资深的后端架构师,精通 RESTful API 设计。请帮我设计一套电商订单系统的 API 接口。
## 业务背景
一个 B2C 电商平台,用户可以浏览商品、下单购买、查看订单状态。
## 功能需求
- 订单模块:创建订单、查询订单列表、查询订单详情、取消订单、支付订单
- 购物车模块:添加商品、修改数量、删除商品、查看购物车
## 设计要求
1. 遵循 RESTful 规范
2. URL 使用名词复数,小写+连字符
3. 正确使用 HTTP 方法
4. 统一的响应格式
5. 版本控制:/v1/
AI 输出示例:
| 方法 | URL | 描述 |
|---|---|---|
POST |
/v1/orders |
创建订单 |
GET |
/v1/orders |
查询订单列表 |
GET |
/v1/orders/{id} |
查询订单详情 |
PATCH |
/v1/orders/{id}/status |
更新订单状态(取消/支付) |
GET |
/v1/users/{id}/cart |
获取购物车 |
POST |
/v1/users/{id}/cart/items |
添加商品到购物车 |
PATCH |
/v1/users/{id}/cart/items/{itemId} |
修改购物车商品数量 |
DELETE |
/v1/users/{id}/cart/items/{itemId} |
删除购物车商品 |
9.3 AI 辅助设计的注意事项
| 注意点 | 说明 |
|---|---|
| 提供完整上下文 | 业务背景、用户角色、数据关系都要说清楚 |
| 明确约束条件 | 命名规范、版本策略、响应格式等要提前定义 |
| 迭代优化 | 第一次输出可能不完美,追问细节、要求修改 |
| 人工审核 | AI 生成的内容需要人工检查是否符合业务需求 |
| 补充边界情况 | 让 AI 考虑错误处理、权限控制、分页等边界情况 |
- "请补充每个接口的错误响应示例"
- "请考虑分页、排序、过滤参数"
- "请添加接口的权限控制说明"
- "请检查是否符合 RESTful 最佳实践"
名词速查表
| 名词 | 英文 | 解释 |
|---|---|---|
| API | Application Programming Interface | 程序之间对话的约定 |
| REST | Representational State Transfer | 一种架构风格,用 URL 标识资源 |
| 资源 | Resource | REST 架构的核心概念,有唯一标识(URL) |
| 幂等性 | Idempotency | 多次执行结果相同 |
| 状态码 | Status Code | HTTP 协议定义的响应状态 |
| 版本控制 | Versioning | 让新旧 API 并存,平滑升级 |
| 请求体 | Request Body | POST/PUT/PATCH 请求携带的数据 |
| 响应体 | Response Body | 服务器返回的数据 |
| Header | Header | 请求/响应的元数据(如 Content-Type) |
| 认证 | Authentication | 验证"你是谁"(登录、Token) |
| 授权 | Authorization | 验证"你能做什么"(权限) |