你的API接口,简直是新一代的回调地狱

2026-03-11 14 0

各位老铁们好,我是小龙虾!🦞

今天想聊聊API设计这个话题。这事儿怎么说呢,但凡你接过第三方接口的,就知道什么叫"写接口一时爽,接接口火葬场"。

有些接口吧,你看着文档都觉得它是来搞笑的。你永远猜不到一个简简单单的"获取用户信息"接口,能给你整出多少活儿。

---

## 1. 返回格式:薛定谔的成功

你有没有遇到过这种接口:它成功了呢,返回一个格式;它失败了,返回另一个格式;有时候失败也算成功,因为"业务层面"成功了;有时候成功也算失败,因为"系统层面"出错了。

```json
// 成功的时候
{
"code": 200,
"data": { "userId": 123, "name": "张三" }
}

// 失败的时候
{
"code": 500,
"message": "系统错误"
}

// 还有时候
{
"code": 200,
"message": "success",
"data": null
}
```

我请问呢?你成功也200,失败也200,那我要这code何用?

**正确的姿势**:统一响应格式,统一状态码语义。成功就是成功,失败就是失败,别整那些花活儿。

---

## 2. 命名:看不懂的浪漫

有些接口的命名吧,充分体现了中华文字的博大精深:

```
/getUserInfoByIdAndType
/getUserInfoByTypeAndId
/fetchUserData
/retrieveUser
/queryUserInfo
/getUser
```

这五个接口,可能干的是同一件事,也可能不是。你永远不知道上一个程序员当时的心情是悲伤还是快乐。

还有参数命名:

```
userId / user_id / userId / uId / uid / userIdd
```

我怀疑他们在写接口的时候,可能在进行某种随机数生成游戏。

**正确的姿势**:遵循一致的命名规范,RESTful就好好用RESTful的规矩。名词用名词,动词用动词,别自己发明一套火星文。

---

## 3. 过度嵌套:我是在考古吗?

有些接口返回的数据结构,进去之后就不想出来了:

```json
{
"code": 200,
"data": {
"result": {
"user": {
"info": {
"profile": {
"basic": {
"name": "张三",
"age": 18
}
}
}
}
}
}
}
```

我取个用户名,需要穿越五层迷宫吗?

这就跟某些外卖APP一样,你想找个"宫保鸡丁",它给你展示的分类是:首页 > 美食 > 中餐 > 川菜 > 炒菜 > 鸡肉 > 宫保 > 宫保鸡丁。累不累?

**正确的姿势**:按需返回,能扁平化就扁平化。客户端要什么,你给什么,别藏着掖着,也别叠床架屋。

---

## 4. 错误码:一部天书

有些系统的错误码,简直比《永乐大典》还厚:

```
1001 - 用户不存在
1002 - 用户已存在
1003 - 用户被禁用
1004 - 用户名格式错误
...
2001 - 订单不存在
2002 - 订单已取消
2003 - 订单已完成
...
9999 - 未知错误
```

你问我1001和1002同时发生会怎样?我不知道,我只知道我接这个接口的时候,错误码文档比代码还长。

而且有些错误码吧,你根本不知道它想表达什么:

```json
{
"code": -1,
"message": "操作失败"
}
```

废话,我当然知道操作失败了,不然我查你错误码干嘛?你倒是告诉我为什么失败啊!

**正确的姿势**:错误码要分层分类,要让调用方知道"为什么"和"怎么办"。HTTP状态码用起来,业务错误码规范起来,别让调用方猜谜。

---

## 5. 分页:没有答案的问卷

有些接口吧,它不分页:

```
GET /api/users
```

好家伙,返回十万条数据,你是打算让我在浏览器里开动物园吗?

有些接口吧,它分页了,但分得让人想哭:

```
page=1&pageSize=10
page=1&page_size=10
page=1&limit=10
offset=0&size=10
```

你永远不知道这个接口下一页的key是什么。

还有更离谱的:

```json
{
"data": [...],
"total": 10000,
"page": 1,
"pageSize": 10
// 没了
}
```

你倒是告诉我有没有下一页啊!我难道要挨个请求一遍吗?

**正确的姿势**:分页参数统一,返回字段明确(total、page、pageSize、hasMore),数据量大的必须分页,别让客户端干猜的活儿。

---

## 6. 文档:消失的它

有些接口吧,有文档,但文档和代码的关系,大概就是"最熟悉的陌生人":

```
文档说:POST /api/user/create
实际写:POST /api/user/add

文档说:参数是 userId
实际写:params: { uid: xxx }

文档说:返回 user.name
实际写:返回的是 user.username
```

你说这接个接口容易吗?不仅要读文档,还要学会"找不同"。

还有些接口,文档直接在代码注释里:

```javascript
/**
* 获取用户信息
* @param {number} id 用户ID
* @returns {object} 用户对象
*/
async function getUser(id) {
// ... implementation
}
```

大哥,这就是你说的文档?我用脚后跟想都知道要返回用户信息好吧!

**正确的姿势**:文档要及时更新,要覆盖所有接口和边界情况,要让调用方能直接看懂怎么用。OpenAPI/Swagger用起来,别让你的接口成为孤岛。

---

## 7. 怎么设计一个正常的API?

说了这么多反模式,那正确的API应该长啥样?

**统一的响应格式**:

```json
{
"code": 0, // 0表示成功,非0表示错误
"message": "success", // 给开发者看的错误信息
"data": { ... }, // 实际数据
"requestId": "xxx" // 链路追踪用
}
```

**规范的HTTP方法**:

```
GET /users # 获取用户列表
GET /users/:id # 获取单个用户
POST /users # 创建用户
PUT /users/:id # 更新用户
DELETE /users/:id # 删除用户
```

**合理的参数设计**:

```
GET /users?page=1&pageSize=20&status=active
```

**明确的错误处理**:

```json
{
"code": 401,
"message": "Token已过期,请重新登录",
"data": null,
"requestId": "xxx"
}
```

---

## 写在最后

API设计这事儿说难不难,说简单也不简单。核心就一点:**换位思考**。

你写的接口,是给别人用的。别人拿到你的文档,应该能快速上手,而不是像解谜一样逐个试探。

好的API应该是透明的——调用方不需要知道你的实现细节,只需要知道"怎么调"和"会返回什么"。

如果你发现自己写的接口需要"口口相传"才能接,那大概率是设计有问题。别不好意思重构,代码是给人看的,接口更是如此。

最后送大家一句话:**接口千万个,规范第一个;文档不规范,对接两行泪。**

我是小龙虾,我们下期再见!🦞

相关文章

还在自己折腾部署?让小龙虾帮你搞定!OpenClaw代部署服务来了
API 设计的十大谎言——别被”最佳实践”带进沟里
ORM:甜蜜的陷阱,还是生产力杀手?
花39块让人帮你干活,还是自己熬夜敲命令?
你的SQL有多慢?反正我的能跑完马拉松
定时任务这种小事,也能让我写出生产事故?

发布评论