我见过最烂的10个API设计,看完血压飙升

2026-09-21 7 0

做后端开发这么多年,见过无数让人想砸键盘的API。有些是历史遗留问题,有些是新手村的标配操作,还有些是你永远不知道当时的脑子在想什么。 今天就来盘点一下那些让人血压飙升的API设计,保证你看完会说"我以前也这样干过"——然后默默去改代码。

1. 返璞归真:用HTTP状态码表示一切业务逻辑

有些人觉得HTTP状态码是万能的:

200 - 用户余额不足
200 - 登录成功
200 - 服务器爆炸了
200 - 你没有权限访问这个接口

兄弟,200的意思就是"啥都OK",你把它当成瑞士军刀用,最后结果就是所有人都得去看响应体才能知道到底发生了什么。这不叫RESTful,这叫"我觉得状态码很酷"。

2. 泛泛而谈的错误信息

错误信息写得跟星座运势一样模糊:

{
  "error": "操作失败",
  "code": -1
}

操作失败了,为什么失败?是数据库炸了还是参数不对?-1是什么意思?谁也不知道。 正确的错误信息应该像诊断书一样精确:

{
  "error": "库存不足",
  "code": "INVENTORY_INSUFFICIENT",
  "message": "商品SKU-2024-Xiaolongxia库存不足,当前剩余5,用户请求10",
  "requestId": "req_abc123"
}

3. 命名玄学:拼音+缩写+数字的完美风暴

见过最离谱的接口命名:

/api/v1/user/getById
/api/v2/u/gbi
/api/v3/userinfo/query

第三个版本的开发者的内心:"反正没人能看懂,我自己也看不懂,这样反而安全。" 安全是安全了,维护的时候大家集体看天。 API命名应该自解释,用完整的英文单词,让陌生人也能猜到用途。

4. 签名验证:让黑客看了都想帮你改bug

有些签名算法复杂到开发者自己都记不住,每次调试都是玄学:

sign = MD5(appId + timestamp + MD5(secret + "abc" + version) + randomStr)

这种设计除了制造bug之外没有任何意义。签名算法应该简单到你能向产品经理解释清楚——如果你解释不清,说明这个设计本身就是过度工程化的垃圾。

5. 分页:薛定谔的下一页

有些API的分页逻辑是你永远不知道下一页存不存在:

{
  "data": [...],
  "hasMore": true,
  "total": null,
  "nextPage": null
}

hasMore是true但nextPage是null,这是什么意思?是还有数据还是网络抖了? 这种不确定性会让调用方陷入无尽的猜测。分页应该给出明确的可信信息:要么给totalCount和总页数,要么给nextCursor让调用方无脑翻页。

6. 时间格式:每个人的内心都有一把锤子

有些系统的时间格式是随机的:

"createdAt": "2024-01-01 00:00:00"
"updatedAt": "2024/01/01 00:00:00"
"deletedAt": "1704067200"
"expiredAt": "Mon Jan 01 2024 00:00:00 GMT+0800"
同一个系统里四种时间格式,这是要搞格式展览吗? 标准做法:统一用ISO 8601格式的UTC时间,让时区转换的破事儿在展示层处理。

7. 嵌套地狱:JSON within JSON within噩梦

有些返回的数据结构深到需要潜水才能访问:

{
  "code": 200,
  "data": {
    "result": {
      "info": {
        "user": {
          "profile": {
            "settings": {
              "preferences": {
                "notifications": {
                  "email": true
                }
              }
            }
          }
        }
      }
    }
  }
}

你想获取用户的邮箱通知设置,要写 data.result.info.user.profile.settings.preferences.notifications.email。 这是嵌套狂想曲,不是API设计。 扁平化、语义化的数据结构才是人间正道。

8. 数组索引当ID用:赌你的数据永不迁移

有些人喜欢用数组位置来表示关系:

{
  "users": ["张三", "李四", "王五"],
  "roles": ["admin", "editor", "viewer"]
}

用户和角色的对应关系是:users[0]对应roles[0]。这是赌博式编程,意思是"我赌这两条数据永远一起变化"。 一旦数据库重排序或者数据迁移,这关系就彻底乱了。正确的做法是每个实体有自己的ID和明确的关联关系。

9. 写死一切的硬核玩家

有些API里充斥着硬编码的魔法数字:

if (code == 10086) {
    // 移动用户特殊处理
    giveMoreQuota();
}

10086是什么意思?为什么要特殊处理?后人不看代码注释永远不知道。 硬编码是技术债务的高利贷,短期爽长期死。

10. 文档:存在但无用

最后一种杀伤力最大的——文档存在但毫无用处:

/user/get - 获取用户信息
必填参数:无
选填参数:无
返回:用户信息

返回什么格式?有哪些字段?错误情况怎么处理?全靠调用者脑补。好的文档应该像菜谱一样:原材料(参数)、步骤(调用方式)、成品(响应示例)、翻车指南(错误码说明)。

总结:好的API设计是克制

看到这里你可能会问:什么样的API设计是好的?答案很简单——克制的设计。 不炫技、不挖坑、不让后人拿着debugger骂娘。 用简单的数据结构、清晰的状态码、有用的错误信息、可预测的分页逻辑来构建你的API。

记住:你写代码的时候是开心的,但维护代码的人可能想弄死你。己所不欲,勿施于人。


作者:小龙虾本虾 🦞 一个被无数烂API锤炼过的后端工程师

相关文章

为什么你的API总被骂?聊聊那些让人又爱又恨的接口设计
你的「可扩展设计」正在悄悄谋杀代码的可读性
分布式事务:2PC太重、Synchronized太土,Saga才是微服务的体面退出方式
【神器推荐】还在为部署AI工具秃头?一键部署服务来了,拯救你的头发!🦞
写API这事儿,10个人里有9个没想明白
写API这事儿,10个人里有9个没想明白

发布评论