RESTful API 设计进阶:超越 CRUD 的工程化实践

每个后端开发者都会设计 API,但设计好 API 是另一回事。本文不讲基础的 REST 规范,而是聚焦实际项目中常见的工程问题。

一、分页设计

1.1 基于偏移量的分页

GET /articles?page=2&count=20

优点:简单直观。缺点:数据量大时 OFFSET 性能差,且并发写入时会出现数据偏移。

1.2 基于游标的分页

GET /articles?cursor=eyJpZCI6MTAwfQ==&count=20

游标通常是上一页最后一条记录的 ID 或时间戳,经过 Base64 编码。优点:性能稳定,适合无限滚动。

{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTIwfQ==",
    "has_more": true
  }
}

二、过滤与排序

不要给每个字段都加查询参数。推荐统一的过滤语法:

GET /articles?filter=category:eq:ai,status:in:draft,published&sort=-created_at,title
  • `eq`:等于
  • `in`:在列表中
  • `gt`、`lt`:大于、小于
  • `-created_at`:降序排序

三、错误响应标准化

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "请求参数不合法",
    "details": [
      {
        "field": "email",
        "message": "邮箱格式不正确",
        "value": "not-an-email"
      }
    ],
    "request_id": "req_abc123"
  }
}

关键要素:

  • `code`:机器可读的错误码,前端可以据此做分支处理
  • `request_id`:方便追踪日志
  • `details`:字段级别的错误说明

四、版本管理

推荐 URL 路径版本:

GET /v1/articles
GET /v2/articles

不推荐 Header 版本,因为 URL 版本更直观,缓存和日志也更容易处理。

版本升级原则:

  • 新增字段不需要新版本
  • 删除或修改已有字段必须新版本
  • 旧版本至少维护 6 个月

五、幂等性设计

PUT 和 DELETE 天然幂等,但 POST 不是。对于支付、下单等关键操作,需要实现幂等键:

POST /orders
Idempotency-Key: order_abc123_unique

服务端收到请求后:

  1. 检查该 key 是否已处理过
  2. 如果是,直接返回之前的结果
  3. 如果否,处理请求并记录 key 和结果

六、批量操作

不要让前端循环调用单条接口。提供批量端点:

POST /articles/batch
{
  "operations": [
    {"action": "create", "data": {"title": "文章1", "content": "..."}},
    {"action": "update", "id": 42, "data": {"title": "更新标题"}},
    {"action": "delete", "id": 15}
  ]
}

响应:

{
  "results": [
    {"status": "success", "data": {"id": 100}},
    {"status": "success", "data": {"id": 42}},
    {"status": "error", "error": {"code": "NOT_FOUND"}}
  ]
}

七、限流响应

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1714500000
Retry-After: 60

前端可以根据 Retry-After 自动重试。

八、文档即代码

用 OpenAPI 3.0 描述你的 API,然后:

  • 自动生成交互式文档(Swagger UI)
  • 自动生成客户端 SDK
  • 作为接口测试的基准
  • CI 中校验实现是否符合文档

好的 API 设计是后端工程化的核心能力。它不是一次性的文档工作,而是需要持续迭代的系统工程。