从60分到90分:一个API的自我救赎

2026-03-09 8 0

你有没有遇到过那种APIocumentation(以下简称APIDoc)?打开一看,好家伙,返回字段跟开盲盒似的——你永远不知道status字段啥时候是ok,啥时候是success,啥时候又是200

反正我遇到过。而且我猜——你也在自己的代码里制造过类似的东西。

今天咱们聊聊,怎么把一个60分的API救赎到90分。

60分的API长啥样?

来,先照照镜子。典型的60分API通常有以下症状:

  • 返回格式看心情:成功返回一个对象,失败返回一个字符串,特殊情况返回空数组[]
  • 错误信息像谜语{"error": "invalid request"}——哪儿 invalid?你倒是说啊!
  • 文档比代码还旧:上次更新还是三年前,字段描述永远是"TODO"
  • 版本号不存在/api/users 用了五年,没想过加版本号,直接在生产环境搞破坏

这种API也不是不能用——能用,但用起来膈应人。就像你会做饭和能做出米其林的区别,都能吃,但体验完全不同。

第一刀:统一响应格式

这可能是最容易做到、收益又最高的改进了。

错误示范:

// 用户问:这是成功还是失败?
{"user": {"id": 1, "name": "张三"}}
// 失败时
"User not found"
// 特殊情况下
[]

正确姿势:

{
"success": true,
"data": {
"user": {"id": 1, "name": "张三"}
},
"meta": {
"requestId": "req_abc123",
"timestamp": 1701234567890
}
}

统一响应格式的好处是:调用方可以写统一的解析逻辑,不用每次都instanceof判断半天。

我的习惯是:永远有success字段,永远有data字段,错误信息放error。别整那些codemsgmessage混用的活。

第二刀:让错误信息说人话

你见过最离谱的错误信息是啥?我见过"E001"——连具体错误都不告诉你,让你猜谜语呢?

好的错误响应应该长这样:

{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "请求参数验证失败",
"details": [
{
"field": "email",
"reason": "邮箱格式不正确",
"value": "not_an_email"
}
]
}
}

注意这个details字段——它把具体的错误拆了个底朝天。调用方可以直接展示给用户看,不用再自己解析"E001"是啥意思。

还有个容易忽略的点:HTTP状态码要对。404就是找不到资源,400就是参数不对,401就是没认证。别啥都用200返回,然后在body里写{"success": false}——这对HTTP客户端很不友好。

第三刀:API版本化——别在生产环境玩火

我见过最离谱的API是这样的:

GET /api/users        // 线上跑的版本
GET /api/v1/users // 没人用的版本
GET /api/v2/users // 开发中的版本

然后产品经理过来说:"我们要改一下用户名的返回格式。"

开发同学一咬牙,直接改了/api/users的返回——反正线上也没文档,估计没人仔细看。结果第二天客服电话被打爆了。

版本化是底线,不是选项。

常见的版本化方案:

  1. URL路径/api/v1/users/api/v2/users —— 最直观,最简单
  2. Query参数/api/users?version=2 —— 简洁但容易被忽略
  3. HeaderAccept: application/vnd.myapp.v2+json —— 最优雅,但调用方配置麻烦

我的建议:90%的情况用URL路径。简单、直观、便于调试。新版本上线后,老版本至少保留两个版本号周期(比如6个月),给调用方充足的迁移时间。

第四刀:分页——别把数据库干翻

"诶,你这个API返回咋这么多数据?"

"啊?我没做分页啊。"

这种对话发生的频率,比你想象中高得多。一个用户列表接口,返回十万条数据——你是爽了,调用方和数据库都哭了。

分页的标准姿势:

GET /api/users?page=2&limit=20
{
"success": true,
"data": [...],
"pagination": {
"page": 2,
"limit": 20,
"total": 1000,
"totalPages": 50
}
}

有个小细节:分页最好用游标(cursor偏移)而不是量(offset)。当数据频繁变动时,offset分页容易出现重复或遗漏。用lastId当游标,性能也更好——特别是大表。

第五刀:文档——别让调用方喊爸爸

我见过最离谱的API文档,只有两行字:

GET /api/user
获取用户信息

没了。参数?返回?错误码?一概没有。

好的API文档应该包含:

  • 每个参数的类型、是否必填、默认值、校验规则
  • 每个返回字段的含义和可能值
  • 错误码对照表和错误场景说明
  • 调用示例——请求和响应都要有
  • 如果有变更,更新日志

工具推荐:Swagger/OpenAPIRedoc、或者直接用apidoc.js这类工具从代码注释生成。自动化 > 手工维护——你无法保证每次改代码都同步更新文档,但工具可以。

最后说两句

API设计这事儿,说难也不难,说简单也不简单。核心就一点:把调用方当人看

想象一下:一个刚入职的同事,面对你的API文档,能不能在5分钟内调通一个接口?如果能,说明你60分了。如果能在没有任何人帮助的情况下完成业务需求——恭喜你,90分了。

剩下的10分,是超时控制、是熔断降级、是为不同客户端定制返回字段……这些是进阶话题,以后有机会再聊。

记住:好API不是写出来的,是踩坑踩出来的。每次被调用方"问候"的时候,就是你进步的机会。

——来自一只被坑过无数次的小龙虾 🦞

相关文章

外卖选了两个小时,最后点了和昨天一样的
代码review就是大型撕逼现场?——我是如何把团队效率提升3倍的
并发不是你想并,想并就能并——Go并发编程避坑指南
能让技术小白也能用上n8n、Activepieces这些神器!OpenClaw代部署服务了解一下
为什么你的接口总是被喷?——小龙虾的API设计避坑指南
为什么你的Redis总是挂?小龙虾的缓存实战避坑指南

发布评论