API 设计原则与最佳实践

引言

大家好,今天想聊聊 API 设计这个话题。说实话,我刚入行那会儿,对 API 设计完全没概念,觉得能跑就行。结果呢?后来维护自己写的那些“能跑”的接口时,差点没把自己坑死——命名不规范、错误码混乱、文档全靠口口相传,新人接手时一头雾水。

后来踩坑踩多了,慢慢也就总结出一些经验。今天把这些心得整理一下,分享给正在学习或者刚接触后端开发的朋友。虽说不上是什么金科玉律,但都是实战中验证过的做法,希望能帮大家少走弯路。

RESTful 风格:让 URL 说话

首先聊聊 RESTful,这东西已经被说烂了,但我还是觉得它是最值得遵守的设计原则之一。

什么叫“让 URL 说话”?意思就是光看 URL,你就能大概猜到这个接口是干什么的。比如:

GET /users/123/orders

你一看就知道,这是获取 ID 为 123 的用户的所有订单。再比如:

POST /articles

这是创建一篇文章。很简单,对吧?

但我见过不少人的 API 是这样的:

GET /getUserInfo?id=123

POST /createNewArticle

这种就属于“假装 RESTful”,其实还是老一套的命令式风格。URL 里出现了动词,看起来就不够优雅。

我的建议是,资源用名词表示,复数形式比较常见。动作交给 HTTP 方法来完成。下面这些可以当作参考:

GET    /users          # 获取用户列表

GET /users/123 # 获取单个用户

POST /users # 创建用户

PUT /users/123 # 完整更新用户

PATCH /users/123 # 部分更新用户

DELETE /users/123 # 删除用户

坚持用这种风格,代码的可读性和一致性都会好很多。

HTTP 方法用对了,事儿就成了一半

说完 URL,再来说说 HTTP 方法。很多人觉得 GET 和 POST 能搞定一切,干嘛搞那么复杂?这话对初学者来说没问题,但当你需要设计一个严谨的 API 时,方法的选用其实很重要。

GET 用来获取资源,不应该改变服务端状态。简单说就是“只读”。 POST 用来创建资源,有时候也可以用于一些复杂的查询操作。 PUT 是全量更新,意思是你传过来的数据会完全替换掉原来的。所以 PUT 请求通常需要包含资源的完整字段。 PATCH 是局部更新,只传需要修改的字段就好。比如用户想改个昵称,用 PATCH 就很合适:
PATCH /users/123

{

"nickname": "新昵称"

}

DELETE 就不用解释了,删除资源。

这里有个坑很多人会踩:用 GET 方法做有副作用的操作。比如有人为了“简单”,用 GET 触发一些状态变更。这是不对的,GET 必须是幂等的,多次执行不会产生副作用。

还有个词叫“幂等”,简单解释一下:就是同一个请求执行一次和执行多次,结果是一样的。GET、PUT、DELETE 都是幂等的,POST 不是。设计 API 的时候想清楚这一点,能避免很多奇怪的 bug。

状态码别乱用,该是什么就是什么

接下来聊聊状态码。这个东西说大不大,但用好了能省很多沟通成本。

最常见的状态码:

- 200 OK:请求成功,返回数据

- 201 Created:创建资源成功,通常配合 POST 使用

- 400 Bad Request:请求参数有问题,比如缺少必填字段

- 401 Unauthorized:未认证,需要登录

- 403 Forbidden:没有权限访问这个资源

- 404 Not Found:资源不存在

- 500 Internal Server Error:服务器内部错误

我见过不少人,所有错误都返回 200,然后在 body 里写个 {"code": 500, "message": "error"}。这种做法不能说错,但确实不够规范。前端开发者在处理这种响应的时候,往往需要多写一堆判断逻辑。

我的建议是,能用 HTTP 状态码表达的意思,就尽量用状态码。错误信息放在响应 body 里详细说明,这样职责分离,清晰明了。

// 400 错误示例

{

"error": "VALIDATION_ERROR",

"message": "邮箱格式不正确",

"details": [

{

"field": "email",

"message": "请输入有效的邮箱地址"

}

]

}

这种结构就很好,前端可以根据 error 字段做国际化处理,根据 details 展示具体哪个字段有问题。

版本化:给 API 留条后路

API 版本化是个大问题,很多人一开始觉得不需要,等真的需要改接口结构的时候,就傻眼了。

常见的版本化方式有几种:

URL 路径版本化(最常见):
/api/v1/users

/api/v2/users

Header 版本化
Accept: application/vnd.myapp.v2+json
查询参数版本化
/users?version=2

我个人比较推荐 URL 路径版本化,原因很简单——直观。开发和调试的时候,一眼就能看出调用的是哪个版本。

版本化最核心的原则是:旧版本要尽量保持兼容,给客户端足够的迁移时间。不能一声不响就把 v1 停了,那样会害死人。

一般来说,新版本上线后,旧版本至少要保留一到两个版本。等所有客户端都迁移得差不多了,再考虑下线的事儿。

文档和错误处理:好 UX 的关键

最后聊聊文档和错误处理,这两个东西做好了,使用你 API 的人会感谢你的。

先说文档。现在有很多工具可以自动生成 API 文档,比如 Swagger/OpenAPI、Apifox 这些。强烈建议大家用起来,别再写那种 Word 文档了,既不好维护,调试也不方便。

一份好的 API 文档应该包含:

- 每个接口的用途说明

- 请求参数列表(名称、类型、是否必填、示例值)

- 响应结构(成功和失败的都要有)

- 错误码说明

- 认证方式

再说错误处理。除了前面提到的状态码,错误信息也要写得友好。别返回“System error”这种鬼话,用户看到根本不知道发生了什么。

// 不好的错误

{

"error": "error",

"message": "操作失败"

}

// 好的错误

{

"error": "INSUFFICIENT_BALANCE",

"message": "余额不足,请充值后再试",

"code": 1002

}

错误信息要告诉使用者:发生了什么问题、可能的原因、以及建议的下一步操作。这样的 API 用起来才舒服。

总结

好啦,今天聊了 API 设计的几个关键点:RESTful 风格、HTTP 方法的正确使用、状态码的规范、版本化管理、以及文档和错误处理。

这些原则看起来简单,但真正坚持下来并不容易。我自己也经常会在赶进度的时候偷懒,写出一些不那么规范的接口。但长期来看,规范的 API 设计能省下大量维护成本,团队协作也会顺畅很多。

如果你正在学习后端开发,或者刚接手一个 API 项目,不妨从这些小点开始改进。一开始不需要追求完美,慢慢迭代就好。

希望这篇文章对你有帮助。如果有什麼问题或者不同的看法,欢迎在评论区聊聊。我们下期再见!