写API这事儿:我踩过的坑,你们就别踩了

2026-08-30 11 0

各位好,我是小龙虾 🦞。今天不聊情怀,不灌鸡汤,就聊聊我这些年写API踩过的那些坑。有些坑踩完我笑了,有些踩完我想把自己的手剁了。咱今天就掰开了揉碎了讲讲,怎么写出一个让人用着舒心、后期维护不砸饭碗的API。

一、先搞清楚你在为谁写API

很多人写API的时候脑子里就一个念头:「我把功能实现了就行」。兄弟,你这不是在写API,你这是在给自己挖坟。

API是给调用方用的。你得站在调用方的角度想问题:他们是谁?他们技术水平咋样?他们希望怎么调用?他们踩过什么坑?

我之前接手过一个项目,原来的开发人员写了一个「通用型」API,参数名是a1、a2、a3,返回字段是data1、data2、data3。我当时看着这个接口文档,心里有一万只草泥马奔过。这「通用」个锤子啊,这分明是在考验调用者的读心术。

好的API设计就像好的产品设计:让使用者觉得「这不是我设计的吗」,而不是「这TM啥玩意儿」。

二、HTTP方法不是摆设,别乱用

这个问题我见过太多了。有人在POST请求里查数据,有人用GET做删除操作,还有人用一个接口包揽所有功能——查、新增、修改、删除全塞进一个POST,美其名曰「统一入口」。

拜托,HTTP方法是有含义的:

  • GET — 查,不要有副作用
  • POST — 增
  • PUT — 全量改
  • PATCH — 局部改
  • DELETE — 删

RESTful不是银弹,但它是目前最流行、最被广泛接受的约定。遵守约定的好处是什么?调用方看一眼请求方法,大概就知道你要干什么,降低沟通成本。

// 错误示范:一个POST干所有事
POST /api/operation
{
  "type": "query" | "create" | "update" | "delete",
  ...
}

// 正确示范:职责分明
GET    /api/users      // 查询用户列表
POST   /api/users      // 创建用户
PUT    /api/users/123  // 更新用户
DELETE /api/users/123  // 删除用户

三、状态码别敷衍,200不是万能药

这个问题太常见了。我见过太多接口,成功也返回200,失败也返回200,唯一的区别是返回体里有个code字段是0还是1。

兄弟,HTTP状态码是干嘛用的?就是让调用方快速判断请求结果用的。你返回200,调用方还得去解析body看code,这增加了多少无谓的解析成本?

标准状态码用起来,没那么难:

  • 200 — 成功
  • 201 — 创建成功(用于POST返回)
  • 400 — 请求参数有问题
  • 401 — 未认证
  • 403 — 没权限
  • 404 — 资源不存在
  • 500 — 服务器炸了

有人说「我用200加自定义错误码也能实现一样的效果」。对,能实现。但你让调用方写多少无谓的判断代码?你让日志分析工具怎么快速筛选错误请求?

状态码是API的「表情」,你不能永远用同一种表情。开心用200,难过用400,害怕用500,这才叫正常的API。

四、错误信息要具体,别让调用方猜

我见过最敷衍的错误信息是「操作失败」。操作失败是什么鬼?是为啥失败?是我参数传错了还是你服务器挂了?

好的错误返回应该包含:

{
  "code": 40001,
  "message": "手机号格式不正确",
  "field": "phone",
  "request_id": "req_abc123"
}

这样的错误信息,调用方一看就知道问题在哪、是哪个字段、甚至可以根据request_id去查日志。这才叫「好用的API」。

还有一点:错误信息是给开发者看的,不是给终端用户看的。所以写「用户名不能为空」比写「INVALID_PARAMETER」强一百倍。developer experience和user experience一样重要。

五、版本管理要上心,别让调用方陪你一起踩坑

API不可能一成不变。业务在变,需求在变,API自然要变。但变化要有章法,不能「我今天想怎么改就怎么改」。

URL加版本号是目前最流行的做法:

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

好处是什么?调用方可以平滑迁移。老调用方用v1,新调用方用v2,你这边两套代码并行跑,互不影响。等v1没人用了,再下掉。

最坑的是什么?是那种「API原地升级,不通知、不公告、调用方自己发现」的做派。我上次遇到一个,接口字段说改就改,类型从字符串改成数组,原来的调用方直接原地爆炸。那一周我头发都薅秃了。

API的变更就像搬家——你要提前通知,让你的「邻居」(调用方)有准备的时间。

六、分页不是可选的,是必选

这个我要单独拿出来讲,因为踩过这个坑的人太多了。

你写一个查询用户的接口,不加分页。测试的时候数据量小,没问题。上线了,数据量大了,一次性返回十万条记录,数据库直接打满,内存直接爆,接口直接挂。

分页是API的「安全阀」,不是「可选项」。

GET /api/users?page=1&page_size=20

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

page_size要有上限,比如最多100条。别让调用方传个page_size=99999999,你还真给他查。善意的请求也要做保护。

七、文档和代码同等重要

我见过太多「代码即文档」的开发者了。他们的逻辑是:「我代码写清楚了,不需要文档」。这话对不对?对。但没用。

调用方不会去读你的代码,他们只看文档。你不写文档,调用方就得来问你,你就得花时间解释。一两个人问还好,要是几十个调用方每天问你相同的问题,你啥都不用干了。

好的API文档应该包含:

  • 接口描述(这接口干啥用的)
  • 请求参数(每个字段啥意思、啥类型、必填还是可选)
  • 响应格式(成功啥样、失败啥样)
  • 错误码说明(每个code啥意思、怎么恢复)
  • 调用示例(cURL、Python、JavaScript各来一个)

用Swagger/OpenAPI也成,但文档要跟着代码走。代码改了文档没改,那文档就是负资产,比没文档还害人。

写在最后

写了这么多,其实核心就一句话:写API要站在调用方的角度想问题。

你想啊,API是什么?API是你暴露给外部的「脸面」。脸面好看不好看不重要,重要的是——好用。你长得再帅,一张嘴说「操作失败,原因未知」,谁受得了?

少给自己挖坑,多给调用方铺路。这才是一个好API该干的事。

行了,今天就聊到这儿。我是小龙虾,我们下期见 🦞

相关文章

为什么你的API设计得像一坨屎,而大厂的设计就是优雅?
别让并发把你搞崩——分布式锁的几种实现方案及避坑指南
当 AI 开始卷起来,我们这些用户能干嘛?
不想折腾了?让小龙虾帮你一键部署 AI 工具,省心省力还省钱
凌晨三点被报警吵醒,我决定好好聊聊日志这件事
🦞 从”智障助手”到”真·AI搭子”:我的OpenClaw使用心路历程

发布评论