写API这事儿:有人写得跟情书一样优雅,有人写得跟遗书一样潦草

2026-06-21 9 0

我做后端开发这些年,看过的API比看过的电影还多。有的API设计得让人想给作者寄锦旗,有的API设计得让人想寄刀片。今天咱们就来聊聊,怎么把API写得像样,别让它成为下一个开发者的噩梦。


RESTful?不是你想的那种"休息"

很多人听到RESTful就头疼,觉得这玩意儿太理论了。我当年也是这么想的,直到有一次我接手了一个项目,那个API长这样:

/api/getUser
/api/getUserInfo
/api/queryUserById
/api/user/detail?id=1
/api/user_get?id=1

看完了吗?看完你是不是想打人了?同一个项目,五种写法,五种风格,五种精神状态。这就是没有统一RESTful规范的后果。

RESTful的核心说白了就八个字:资源、动作、状态、统一。名词代表资源,动词用HTTP方法表示,状态码告诉你结果怎么样。

GET    /users      # 获取用户列表
GET    /users/1    # 获取ID为1的用户
POST   /users      # 创建新用户
PUT    /users/1    # 完整更新用户
PATCH  /users/1    # 部分更新用户
DELETE /users/1    # 删除用户

这就是标准的RESTful风格。简单、清晰、一致。看到这个路由表,你就知道每个接口是干什么的。


状态码:这玩意儿比验证码还重要

状态码是API的门面。你去餐厅吃饭,服务员跟你说"您的菜在做",然后就没下文了,你慌不慌?API也一样,你调了个接口,返回个200,然后呢?成功了?失败了?数据在哪?

常用状态码,我给大家捋一捋:

2xx - 成功系列
200 OK           # 搞定了
201 Created      # 创建成功
204 No Content   # 成功但没返回内容(常用于DELETE)

4xx - 客户端错误
400 Bad Request  # 你请求的参数有问题
401 Unauthorized # 没登录就想干活?
403 Forbidden    # 登录了也没权限
404 Not Found    # 你要的东西不存在
422 Unprocessable Entity # 参数格式对了但语义不对
429 Too Many Requests # 刷接口刷太狠了兄弟

5xx - 服务器错误
500 Internal Server Error # 我们的问题,不是你的
503 Service Unavailable # 服务暂时不在家

最烦的一种情况是什么?接口返回200,但里面是个错误。这种行为就跟"好的收到"然后已读不回一样让人窝火。


错误处理:别让你的API变成"薛定谔的返回"

好的错误处理应该是这样的:

{
  "code": 40001,
  "message": "用户名不能为空",
  "data": null
}

清晰的错误码,明确的错误信息,可能的话再给点修复建议。用户在调用你接口的时候,可能比你还懵,你得让他知道发生了什么。

我见过最离谱的错误处理是这样的:

{
  "error": true,
  "msg": "出错了",
  "info": "请联系管理员",
  "errorCode": 999
}

兄弟,你这是错误处理还是在叠buff?四种方式表达同一个意思,生怕我猜不出来是哪种错?

我的建议是:统一错误格式,错误码要有分类,文档要写清楚每个错误码的含义。

{
  "code": 40001,
  "message": "用户名不能为空",
  "request_id": "req_abc123",
  "docs": "https://api.example.com/errors#40001"
}

加个request_id是为了方便排查问题。日志里搜一下request_id,完整链路一目了然。这个习惯救过我很多次。


分页:别一口气把数据全吐出来

有些新人写接口,恨不得把所有数据一次返回给前端。用户表有一百万条数据,SELECT * FROM users,直接返回。这不叫接口,这叫DoS攻击。

标准分页应该这样设计:

GET /users?page=1&page_size=20

Response:
{
  "data": [...],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 1000,
    "total_pages": 50
  }
}

page_size别给太大,建议上限100。超过100的一律按100处理,这是对自己的保护,也是对数据库的尊重。

还有一种叫游标分页,适合数据量特别大且实时性要求高的场景:

GET /users?cursor=eyJpZCI6MTAwfQ&page_size=20

这种分页方式性能更稳,不会因为数据新增删除导致重复或遗漏。但实现起来稍微复杂点,看场景选用。


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

接口上线了,v1版本运行得好好的产品突然要加功能,改着改着发现要动原来的结构了,怎么办?直接改?万一有人还在用旧结构呢?

所以,版本管理是必须的:

/api/v1/users
/api/v2/users

新功能走v2,老接口v1继续维护,给个deprecated标记,给用户留足迁移时间。

我见过最骚的操作是:一个接口同时存在v1、v2、v3三个版本,每个版本的实现还略有不同。问为什么要这样?答曰:"历史遗留问题"。这种项目谁接谁倒霉。


安全性:别让你的API成为免费公共厕所

API安全是个老生常谈但总有人踩坑的话题。我见过有人在URL里传密码的:

GET /api/login?username=admin&password=123456

这种接口跟裸奔有什么区别?密码进了服务器日志、浏览器历史、代理服务器日志、CDN日志,四重曝光。密码这种东西,必须走POST body,HTTPS加密。

几个基本的安全措施:

  • 所有接口走HTTPS,别省那点证书钱
  • 敏感操作加身份验证,JWT或者OAuth2都行
  • 请求频率做限制,别让接口被刷爆
  • 输入参数做校验,别相信任何客户端数据
  • 返回数据做脱敏,手机号、身份证号别明文返回

文档:没有文档的API跟没有说明书的产品一样

你设计了一套完美的API,路由清晰、状态码规范、错误处理友好。然后呢?写文档了吗?

没文档的API,等于没写。你自己知道怎么用,别人不知道。产品要对接,测开要测试,下一个后端要接你的班——他们都指着你的文档活呢。

文档要包含什么?

  • 接口列表和功能说明
  • 请求参数格式和示例
  • 返回数据格式和示例
  • 错误码对照表
  • 认证方式说明
  • 调用限制说明

工具推荐:Swagger/OpenAPI是目前最流行的方案,写一次文档,可以同时生成接口测试界面和客户端SDK。省时省力。


写在最后

API设计这事儿,说难不难,说简单也不简单。难的地方不在于你会不会用框架、会不会写代码,而在于你有没有站在调用者的角度想过问题。

好的API应该是这样的:看一眼文档,就能知道怎么用;出错了,能知道错在哪;接入了,能放心地依赖它。这才是API设计应该追求的目标。

下次写接口之前,先问自己三个问题:这个接口别人看得懂吗?出问题了别人能排查吗?万一我要改版了怎么平滑过渡?想清楚这三个问题,你的接口至少不会太差。

愿天下API都是好接口,愿天下开发者都不需要对接烂接口。共勉。

相关文章

ORM这个温柔的陷阱,毁掉了无数年轻程序员的数据库功底
写API就是在写命:那些年我们一起踩过的设计坑
为什么你的API总被吐槽?来自一线工程师的7条血泪教训
一个用户重复下单引发的血案:论API幂等性的正确姿势
做了5年后端,我攒下一肚子API设计反套路
OpenClaw 使用经验分享:我用这只“虾”做了什么骚操作

发布评论