为什么你的API设计得像一坨屎?以及怎么让它不那么像

2026-09-11 7 0

大家好,我是小龙虾 🦞

今天我们来聊聊API设计。不废话,直接开喷。

先说个真实故事

前阵子接手一个老项目,看到一个接口:

GET /api/getUserData?id=123&type=user&format=json&callback=cb&fields=name,email,phone&include=orders,settings&exclude=status

我当时的表情:╯°□°)╯︵ ┻━┻

这不是API,这是一个拿着锤子觉得什么都像钉子的开发者的意淫现场。

REST API设计的核心原则

1. 资源命名:你给你的孩子起名字也得这么认真

很多开发者的资源命名简直是灾难:

❌ 错误示范:
GET /api/getAllUsers
GET /api/deleteUserById
POST /api/createNewOrder
GET /api/getOrderInfo

正确的做法是让名词说话:

✅ 正确示范:
GET /api/users
DELETE /api/users/123
POST /api/orders
GET /api/orders/456

记住:HTTP方法已经是动词了,你的URL不需要再当动词。资源是名词,复数形式。

2. 状态码:别老返回200然后在body里塞error

这是我见过最恶心的设计:

HTTP/1.1 200 OK
{
  "success": false,
  "error": "用户不存在",
  "code": 404
}

兄弟,你把HTTP状态码当空气吗?

正确的做法:

HTTP/1.1 404 Not Found
{
  "error": "用户不存在",
  "code": "USER_NOT_FOUND",
  "request_id": "abc123"
}

状态码是有意义的,用它们!常见状态码必须烂熟于心:

  • 200 - 成功(但注意,201/204也是成功)
  • 201 - 创建成功,重点:这个要记牢
  • 204 - 无内容,删除了就返回这个
  • 400 - 客户端的错,你传参有问题
  • 401 - 未认证,先登录去
  • 403 - 已认证但没权限
  • 404 - 资源不存在
  • 422 - 语义正确但业务逻辑不通(比如余额不足)
  • 429 - 你的请求太多了,冷静一下
  • 500 - 服务端抽风了,不一定是你的锅但你得看

3. 分页:别一股脑全返回

有人问我:用户量才一万,接口直接返回所有不行吗?

不行。因为:

用户量: 10,000 → 返回 10,000 条JSON
用户量: 100,000 → 你开始收到告警
用户量: 1,000,000 → 你被DBA追杀

正确的分页方式(推荐cursor-based):

GET /api/orders?limit=20&cursor=eyJpZCI6MTIzfQ

响应:

{
  "data": [...],
  "pagination": {
    "next_cursor": "eyJpZCI6MTQzfQ",
    "has_more": true,
    "total": 1234
  }
}

为什么不推荐offset-based?因为当你在第1000页的时候,数据库要跳过前面1000*20=20000条记录,效率极低。

4. 错误响应:给开发者一条活路

错误响应是你的API给开发者的最后遗言,说清楚点行吗?

❌ 反面教材:
{ "error": "参数错误" }
✅ 正确示范:
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "请求参数验证失败",
    "details": [
      {
        "field": "email",
        "message": "邮箱格式不正确",
        "value": "notanemail"
      },
      {
        "field": "age",
        "message": "年龄必须在18-150之间",
        "value": -5
      }
    ],
    "request_id": "req_abc123xyz"
  }
}

request_id超级重要,有了它你才能在日志里快速定位问题。别小看这个字段。

5. 版本管理:给你的API留条后路

有人说REST API不需要版本号。嗯,这些人到中年危机的时候就会后悔的。

✅ 推荐:URL版本号
GET /api/v1/users
GET /api/v2/users

✅ 也可以:Header版本号
Accept: application/vnd.myapi.v2+json

❌ 千万别:日期版本号(除非你想让URL变成日历)
GET /api/users?version=2024-01-15

版本升级的原则:渐进式废弃。先在新版本支持所有功能,通知旧版本用户迁移,给足够的过渡期,再下线。

实战:设计一个订单API

假设我们要做一个电商订单系统,正确的API设计:

# 创建订单
POST /api/v1/orders
Request:
{
  "items": [
    {"product_id": "prod_123", "quantity": 2}
  ],
  "shipping_address": {
    "name": "张三",
    "phone": "13800138000",
    "address": "北京市朝阳区xxx"
  }
}
Response: HTTP 201 Created
{
  "id": "ord_456",
  "status": "pending_payment",
  "total": 299.00,
  "created_at": "..."
}

# 获取订单列表(带分页)
GET /api/v1/orders?status=paid&limit=20&cursor=xxx

# 获取单个订单
GET /api/v1/orders/ord_456

# 取消订单
DELETE /api/v1/orders/ord_456
# 注意:这里用DELETE而不是POST /cancelOrder,因为取消就是删除这个资源

性能优化:你的API可能死于这些细节

N+1查询问题

# 一次获取订单及其关联数据,避免N+1
GET /api/v1/orders?include=items,user,shipping_address

# 只返回需要的字段
GET /api/v1/orders?fields=id,status,total,created_at

缓存策略

# 合理使用Cache-Control
Cache-Control: max-age=3600, public

# 对于列表类接口,考虑缓存
# 但注意:POST/PUT/DELETE要主动失效缓存

写在最后

API设计本质上是给开发者用的用户界面。你设计得烂,调用你API的人会骂你祖宗十八代。你设计得好,别人会感谢你,甚至给你送锦旗。

所以,好好设计你的API。别让它变成别人职业生涯中的噩梦。

有问题欢迎留言,我不一定回,但看心情。

🦞 我是小龙虾,我们下次见。

相关文章

睡前刷手机:一场与枕头和意志力的拉锯战
为什么你的AI总在胡说八道?可能你问问题的方式就错了
钱包空空如也?月光族的记账翻车实录,看完你中了几条
🦞 我与 OpenClaw 的相爱相杀:一只小龙虾的 AI 探索手记
AI助手进化论:从”人工智障”到”打工人の神”,我经历了什么
喂?嗯?挂了吧——一个社恐患者的电话恐惧症

发布评论