RESTful已死:为什么你在浪费生命设计”正确”的API

2026-04-10 12 0

RESTful已死:为什么你在浪费生命设计"正确"的API

我见过太多团队为了追求"RESTful规范"吵得面红耳赤,GraphQL和gRPC之间互相鄙视,OpenAPI文档写得比代码还长,但没人说得清楚这一切到底为了什么。

今天我要说一句很多人不敢说的话:你花大量时间设计的"完美API",可能从一开始就是错的。


一个令人不安的事实

大多数后端开发者学习API设计时,第一件事就是背REST原则:资源、动词、状态码。然后呢?然后他们花了大量时间争论PUTPATCH的区别,纠结应该用201还是200,研究HTTP缓存头怎么配。

这些重要吗?某种程度上。但更重要的是:你的API是给谁用的?

如果你的API主要给自家前端用,那你追求的"规范"可能全是无效工作。如果你的API是公开API,那暴露的内部实现细节可能在给自己挖坑。


实战教训:一场"规范化"引发的血案

我曾经参与过一个项目,团队对API规范性有着近乎强迫症的追求:

  • 所有列表接口必须支持分页、排序、筛选
  • 所有更新操作必须区分PUT(完整更新)和PATCH(部分更新)
  • 所有删除操作必须返回204状态码
  • 所有错误必须遵循RFC 7807规范

听起来很美好,对吧?但现实是:

  1. 前端团队抱怨接口响应慢——因为后端花太多时间处理那些"规范化"逻辑
  2. 移动端团队直接绕过这些接口,自己写了一套简化版——因为规范太复杂根本用不上
  3. 文档团队维护着一套比代码还难懂的OpenAPI规范,里面充斥着永远不会被调用的端点

最讽刺的是什么?这个API 90%的调用都来自内部,前端要什么后端早就知道了。那套"完美设计"纯粹是给自己看的表演。


你的API使用者不是机器人

很多人在设计API时陷入一个误区:把API当成数学公式,恨不得用最少的端点、最抽象的资源模型覆盖所有场景。

但API是给人用的,不是给代码静态分析工具用的。

举个例子。假设你在做一个电商系统,传统做法可能是这样:

GET /api/products?category=electronics&min_price=1000&max_price=5000&sort=price&order=asc&page=1&page_size=20

URL长得像一坨屎,但这是"规范"的。

另一种做法:

POST /api/products/search
{
  "category": "electronics",
  "price_range": [1000, 5000],
  "sort": "price_asc",
  "page": 1
}

哪种更好?如果你做的是内部系统,第二种明显更实用:URL参数少了好维护,请求体可以加注释,而且将来扩展字段也方便。

如果你做的是公开API,需要给第三方集成,第一种更合适——符合"可发现性"原则。

问题是:很多人在做内部系统时也在用第一种方案,因为他们觉得这样"更规范"。


gRPC vs REST:不是一个层面的战争

每隔一段时间,就有人跳出来说REST已死,gRPC才是未来。然后另一群人反驳说gRPC太复杂,REST才是正道。

我只想问一句:你们争的是技术,还是自己的技术优越感?

真实情况是:

  • REST:适合浏览器优先、需要广泛兼容性的场景。调试简单,生态成熟。
  • gRPC:适合微服务间高性能通信、强类型契约优先的场景。支持双向流。
  • GraphQL:适合多端(Web/iOS/Android)需要不同数据形状的场景。代价是复杂度上升。
  • WebSocket:适合实时性要求高的场景。不是替代品,是不同场景的工具。

没有银弹。我见过把gRPC用在一台机器上两个进程间通信的团队,也见过在需要实时推送的场景坚持用REST polling的团队。

选型的标准只有一个:你的场景真正需要什么?


版本管理:被神化的最佳实践

几乎所有API设计教程都会告诉你:必须做版本管理,URL里必须有/v1/或者/v2/

但我要告诉你一个反直觉的事实:URL版本控制可能是你最不需要担心的。

看看GitHub API:

GET https://api.github.com/gists/public

没有版本号。GitHub怎么做到的?靠的是强大的向后兼容性。他们宁可维护旧字段,也不轻易破坏现有调用。

当然,GitHub是顶级公司,不是每个团队都能做到。那种情况下该怎么办?

我的建议:

  1. 内部系统:优先做好向后兼容,用header做隐式版本控制就够了
  2. 公开API:如果必须显式版本,先评估维护成本,能用小版本解决的问题不要动不动就大版本升级
  3. 无论什么系统:废弃策略比版本号更重要。你的旧接口打算保留多久?给调用方多少迁移时间?这些才值得花时间设计

错误处理:最容易露馅的地方

如果让我用一个指标判断一个团队API设计水平,我会看他们的错误处理。

烂的API的错误处理长这样:

{
  "code": 1001,
  "message": "操作失败",
  "data": null
}

这个"1001"是什么鬼?客户端开发者怎么知道1001对应的是什么错误?

好的API错误处理长这样:

{
  "error": {
    "code": "INSUFFICIENT_INVENTORY",
    "message": "商品库存不足,当前可用数量:3",
    "details": {
      "product_id": "SKU-2024-001",
      "requested": 10,
      "available": 3
    },
    "trace_id": "req_abc123xyz"
  }
}

关键要素:

  • 错误码是人类可读的字符串,不是数字。调试时搜错误码比搜数字方便一百倍。
  • 消息要给人类看,包含足够上下文。
  • details是给开发者看的结构化数据,客户端代码可以直接拿来用。
  • trace_id用于链路追踪,出问题了你才知道去哪查日志。

好的错误处理是给调用方省时间的,而不是展示你有多严谨。


写在最后

API设计的本质是什么?是让调用方用最小的认知负担完成任务。

不是什么"符合HTTP语义",不是什么"RESTful六大约束",不是什么"GraphQL才是现代化架构"。

。是你对面那个要集成你API的开发者。他可能在凌晨两点被bug叫醒,他可能根本不关心你用的是gRPC还是REST,他只关心两件事:

  1. 这个接口能不能完成我的需求?
  2. 出问题了,我怎么快速定位和解决?

把这两个问题回答好,比什么都强。

至于那些规范?用得上的才学,用不上的先放一边。等你真的遇到了,再去研究也不迟。

别让"最佳实践"成为你偷懒不思考的借口。


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

相关文章

🦞 当 AI 开始”整顿职场”,我决定先整顿它的噱头
OpenClaw 使用经验分享:一个AI助手能有多能打?
OpenClaw 使用经验分享:一个AI助手能有多能打?
为什么你的Prompt总是差点意思?可能是你不懂AI的”脑回路”
你的接口被疯狂调用,用户却骂你系统烂:限流做不好,就是这么丢人
你的HTTP重试,正在慢慢杀死你的系统

发布评论