引言
API 不是实现细节,API 是产品。它的用户是其他开发者——你的同事、客户公司的前端团队、或调用你服务的第三方。设计糟糕的 API 会让调用方困惑、引发 bug、拖慢团队开发速度;设计良好的 API 像一份优秀文档,调用方几乎无需阅读说明就能正确使用。
当今三大 API 范式:REST(成熟、通用)、gRPC(高性能、强类型)、GraphQL(灵活、客户端驱动)。它们并非互相替代,而是可以共存。本文将系统讲解设计规范、版本管理、错误处理、分页策略和文档生成。
目录
- 1. REST API 设计规范
- 2. REST API 完整示例
- 3. gRPC 入门
- 4. gRPC 四种通信模式
- 5. GraphQL 基础
- 6. API 版本管理策略
- 7. 错误码设计
- 8. 分页策略
- 9. API 文档工具
- 10. 总结对比
- 延伸阅读
1. REST API 设计规范
1.1 URL 命名规则
REST 将后端数据抽象为资源(Resource),URL 表示资源,HTTP 方法表示操作。
✅ 好设计:
GET /api/v1/users # 列表
GET /api/v1/users/123 # 单个
POST /api/v1/users # 创建
PUT /api/v1/users/123 # 全量更新
PATCH /api/v1/users/123 # 部分更新
DELETE /api/v1/users/123 # 删除
GET /api/v1/users/123/orders # 子资源
❌ 反模式:/api/getUser?id=123、/api/createUser、/api/users_list
规则:复数名词、小写连字符、URL 不用动词、子资源最多两层嵌套。
1.2 HTTP 方法语义
| 方法 | 幂等 | 用途 |
|---|---|---|
| GET | ✅ | 读取 |
| POST | ❌ | 创建 |
| PUT | ✅ | 全量替换 |
| PATCH | ❌ | 部分更新 |
| DELETE | ✅ | 删除 |
1.3 状态码使用
| 状态码 | 含义 | 场景 |
|---|---|---|
| 200 OK | 成功 | GET/PUT/PATCH/DELETE |
| 201 Created | 创建成功 | POST |
| 204 No Content | 成功无返回 | DELETE |
| 400 Bad Request | 参数错误 | 校验失败 |
| 401 Unauthorized | 未认证 | Token 缺失或无效 |
| 403 Forbidden | 无权限 | 权限不足 |
| 404 Not Found | 不存在 | ID 无效 |
| 409 Conflict | 冲突 | 重复创建 |
| 429 Too Many Requests | 限流 | 请求过快 |
1.4 HATEOAS
响应中包含下一步操作链接,让客户端动态发现 API 能力:
{
"id": 123,
"name": "Alice",
"_links": {
"self": { "href": "/api/v1/users/123" },
"orders": { "href": "/api/v1/users/123/orders" },
"delete": { "href": "/api/v1/users/123", "method": "DELETE" }
}
}
HATEOAS 实现复杂,仅在高度动态的系统中推荐。
2. REST API 完整示例
创建用户:
POST /api/v1/users HTTP/1.1
Content-Type: application/json
Authorization: Bearer <token>
{ "name": "Alice", "email": "alice@example.com", "role": "admin" }
响应(201 Created):
{
"id": 123,
"name": "Alice",
"email": "alice@example.com",
"role": "admin",
"created_at": "2025-11-22T10:00:00Z"
}
错误响应(422):
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": [
{ "field": "email", "issue": "Invalid email format" }
]
}
}
3. gRPC 入门
gRPC 是 Google 开源的高性能 RPC 框架,使用 Protocol Buffers 作为接口定义语言和序列化格式。
syntax = "proto3";
package user.v1;
service UserService {
rpc GetUser (GetUserRequest) returns (User);
rpc CreateUser (CreateUserRequest) returns (User);
}
message User {
int64 id = 1;
string name = 2;
string email = 3;
string created_at = 4;
}
message GetUserRequest { int64 id = 1; }
message CreateUserRequest { string name = 1; string email = 2; }
优势:强类型契约、二进制序列化(比 JSON 小 3-10 倍)、HTTP/2 多路复用、自动生成多语言客户端。
4. gRPC 四种通信模式
1. Unary(一元):普通请求-响应。
rpc GetUser (GetUserRequest) returns (User);
2. Server Streaming:服务器返回数据流。
rpc WatchOrders (WatchOrdersRequest) returns (stream Order);
stream, _ := client.WatchOrders(ctx, &WatchOrdersRequest{UserID: 123})
for {
order, err := stream.Recv()
if err == io.EOF { break }
fmt.Println("New order:", order)
}
3. Client Streaming:客户端发送数据流。
rpc UploadMetrics (stream Metric) returns (UploadSummary);
4. Bidirectional Streaming:双向流,适用于聊天、协作。
rpc Chat (stream ChatMessage) returns (stream ChatMessage);
5. GraphQL 基础
GraphQL 让客户端精确指定需要的字段,避免 REST 的 over-fetching 和 under-fetching。
type User {
id: ID!
name: String!
email: String!
orders: [Order!]!
}
type Query {
user(id: ID!): User
users(limit: Int = 20, cursor: String): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): User!
}
type Subscription {
orderStatusChanged(userId: ID!): Order!
}
Query 示例:
query {
user(id: "123") {
name
orders { id amount }
}
}
适用:移动端(精准字段)、复杂关联查询、多客户端差异化需求。
6. API 版本管理策略
| 策略 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| URL 路径 | /api/v1/users | 直观、易缓存 | URL 膨胀 |
| 查询参数 | /api/users?version=1 | 简单 | 缓存不友好 |
| Header | Accept: application/vnd.api.v1+json | 符合 REST 语义 | 客户端不易感知 |
推荐:对外 API 用 URL 路径,内部 API 可用 Header。
废弃策略:宣布废弃日期(至少提前 6 个月)→ 返回 Sunset / Deprecation 头 → 提供迁移指南 → 旧版本维护到废弃日。
7. 错误码设计
采用 RFC 7807 Problem Details 标准:
{
"type": "https://api.example.com/errors/user-not-found",
"title": "User Not Found",
"status": 404,
"detail": "User with ID 123 does not exist",
"instance": "/api/v1/users/123",
"trace_id": "abc-123-def",
"timestamp": "2025-11-22T10:00:00Z"
}
原则:
- 用字符串错误码(
USER_NOT_FOUND)而非数字码 - 每个错误码对应唯一文档页面
- 区分 4xx(客户端错误)和 5xx(服务器错误)
- 包含
trace_id便于排查
8. 分页策略
Offset Pagination:
GET /api/v1/users?offset=20&limit=10
优点:简单、可跳页。缺点:插入/删除时重复或遗漏,大偏移性能差。
Cursor Pagination:
GET /api/v1/users?cursor=eyJpZCI6MTB9&limit=10
{
"data": [...],
"pagination": { "next_cursor": "eyJpZCI6MjB9", "has_more": true }
}
优点:稳定、性能好。缺点:无法跳页。
Keyset Pagination:基于复合索引(如 created_at, id)做 WHERE 比较,适合时间序列,性能最优,无 offset 性能退化。
推荐:对外 API 默认 Cursor,后台管理用 Offset,大数据流用 Keyset。
9. API 文档工具
- OpenAPI / Swagger:REST 标准规范,可生成客户端、Mock、交互文档
- gRPC Gateway:将 gRPC 转换为 REST/JSON,便于 Web 客户端
- GraphiQL / Apollo Studio:GraphQL 交互文档与调试
- Buf.build:gRPC/protobuf 的现代化 registry
OpenAPI 片段:
paths:
/api/v1/users/{id}:
get:
parameters:
- { name: id, in: path, required: true, schema: { type: integer } }
responses:
'200': { description: User found }
10. 总结对比
| 维度 | REST | gRPC | GraphQL |
|---|---|---|---|
| 协议 | HTTP/1.1 | HTTP/2 | HTTP/1.1 |
| 数据格式 | JSON | Protobuf | JSON |
| 类型系统 | 弱 | 强 | 强 |
| 性能 | 中 | 高 | 中 |
| 客户端灵活性 | 低 | 低 | 高 |
| 浏览器支持 | 优秀 | 需 grpc-web | 优秀 |
| 适用 | 对外 API | 微服务间通信 | 移动端、复杂前端 |
推荐组合:对外 REST + 内部 gRPC + 移动端 GraphQL,按场景组合。
延伸阅读
- Roy Fielding, Architectural Styles and the Design of Network-based Software Architectures
- Google API Design Guide
- GraphQL 官方文档
- gRPC 官方文档
- RFC 7807: Problem Details for HTTP APIs
- OpenAPI Specification
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。