API 设计的一些想法

做了几年前后端对接,见过好的 API,也见过让人抓狂的。这里记录一些经验。

RESTful 是好,但别教条

有些团队非要严格执行 RESTful,结果:

GET  /users          # 获取列表
POST /users          # 创建
GET  /users/:id      # 获取详情
PUT  /users/:id      # 更新
DELETE /users/:id    # 删除

看起来很标准对吧?但遇到复杂场景就尴尬了:

  • 批量删除怎么办?
  • 搜索算 GET 还是 POST?
  • 登录算哪个资源?

我的建议:RESTful 作为基础风格,特殊情况该破就破。

// 批量操作
POST /users/batch-delete

// 复杂查询
POST /users/search

// 登录
POST /auth/login

统一响应格式

interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

不管成功失败,格式一致。前端处理起来方便很多。

错误响应也要有结构:

{
  "code": 40001,
  "message": "参数错误",
  "errors": [
    { "field": "email", "message": "邮箱格式不正确" }
  ]
}

分页的坑

最头疼的是分页参数不统一。有的用 page/size,有的用 offset/limit,还有的自己发明格式。

建议:

interface PaginationParams {
  page: number;  // 从 1 开始
  pageSize: number;
}

interface PaginatedResponse<T> {
  list: T[];
  total: number;
  page: number;
  pageSize: number;
  totalPages: number;
}

版本控制

API 一定会变,提前规划好版本策略。

两种常见方式:

# URL 版本
/api/v1/users
/api/v2/users

# Header 版本
GET /api/users
Accept: application/vnd.myapi.v2+json

URL 版本更直观,Header 更灵活。我们用的 URL 版本,简单粗暴。

文档

没有文档的 API 等于不存在。

我们用 Swagger/OpenAPI,自动生成文档:

openapi: 3.0.0
paths:
  /users:
    get:
      summary: 获取用户列表
      parameters:
        - name: page
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: 成功

前端可以直接看文档,不用再去问后端了。

最后

好的 API 设计是双向的。前端要多提需求,后端要多考虑使用场景。别搞成后端写完前端骂娘的循环。