💡 Key Takeaways
- Principle 1: Design Your API Like a Product, Not a Database Wrapper
- Principle 2: Embrace HTTP Status Codes Properly (But Don't Overthink Them)
- Principle 3: Version Your API From Day One (And Do It Right)
- Principle 4: Design Intuitive Resource Naming and URL Structures
我仍然记得有一天我必须向我们的首席执行官解释,为什么我们的移动应用像森林大火一样快速消耗用户的数据套餐。那是2016年,我在一家金融科技初创公司担任首席API架构师已有三年。我们的REST API每次应用检查账户余额时,都返回整个用户对象——包括以base64编码的个人资料图片。我们正在大量流失客户,而我设计的API正在扼杀我们。
💡 重点要点
- 原则1:将您的API设计为产品,而不是数据库封装
- 原则2:正确使用HTTP状态代码(但不要想得太复杂)
- 原则3:从第一天起给您的API进行版本控制(并做到正确)
- 原则4:设计直观的资源命名和URL结构
这个痛苦的教训教会了我一个关键点:REST API设计不仅仅是让事情能够工作。它是关于让它们在真实世界条件下高效地工作,尤其是在教科书从未提到的情况下。在过去的十二年里,我为从10人的初创企业到财富500强企业构建API,我看到了许多相同的错误一遍又一遍地重演——而我自己也犯了大多数错误。
今天,我要分享十条改变我设计API方式的原则。这些不是来自学术论文的理论概念。它们是在每日电量数百万的生产环境中经过实战检验的指导方针。无论您是构建第一个API还是重构第十个,这些原则都将帮助您创建开发者真正想要使用的接口。
原则1:将您的API设计为产品,而不是数据库封装
我在REST API设计中看到的最大错误是将API视为数据库表上的薄层。我审核了数百个API,其中端点与数据库架构一一对应,暴露了不应该公开的内部实现细节。这种方法创建了脆弱的接口,每当您的数据模型演变时就会崩溃。
当我加入我目前的公司担任平台工程副总裁时,我们的API有47个端点,直接映射到我们的PostgreSQL架构。更改一个列名需要在23个不同的客户端应用程序之间协调更新。这种技术债务窒息了我们创新的能力。
相反,考虑将您的API视为具有独立生命周期、版本控制策略和用户体验考量的产品。您的API消费者不关心您的数据库规范化策略或内部微服务架构。他们关心的是以高效的方式完成特定任务。
例如,与其为/users、/user_profiles、/user_preferences和/user_settings暴露单独的端点,不如考虑您的API消费者真正需要什么。在大多数情况下,他们想要一个统一的/users/{id}端点,该端点返回一个经过深思熟虑的资源。使用像?fields=profile,preferences这样的查询参数来让消费者确切地请求他们需要的内容。
我在一家医疗SaaS公司实施了这种方法,我们将API的表面面积从89个端点减少到34个,同时实际上增加了功能。响应时间下降了43%,因为我们消除了多次请求组装基本信息所带来的繁琐。更重要的是,我们的API文档变得易于理解,开发者的入职时间从两周缩短到三天。
关键是理解您API的领域模型,这可能与您的持久化模型有显著差异。花时间与您的API消费者交谈,无论他们是内部前端团队还是外部合作伙伴,并理解他们的工作流程。围绕他们的思维模型设计资源,而不是您的数据库表。
原则2:正确使用HTTP状态代码(但不要想得太复杂)
HTTP状态代码是您的API与客户端的首要沟通方式,但我经常看到它们被错误使用或完全被忽略。我曾审核过一个API,该API返回200 OK作为每个响应,包括错误,实际状态则埋藏在JSON字段中。开发者认为他们“总是成功”是很有帮助的,但实际上这破坏了每个HTTP客户端库的错误处理。
您不需要记住所有63个HTTP状态代码,但绝对需要正确使用核心状态代码。以下是我基于十二年生产经验的实用分类:
- 200 OK:成功的GET、PUT或PATCH,返回内容
- 201 Created:成功的POST,创建资源(包括Location头部)
- 204 No Content:成功的DELETE或更新,返回空
- 400 Bad Request:客户端发送了无效数据(包括特定的验证错误)
- 401 Unauthorized:需要身份验证或身份验证失败
- 403 Forbidden:已验证但缺乏权限
- 404 Not Found:资源不存在
- 409 Conflict:请求与当前状态冲突(重复创建、版本不匹配)
- 422 Unprocessable Entity:语法正确但语义无效
- 429 Too Many Requests:超出速率限制(包括Retry-After头部)
- 500 Internal Server Error:您的端发生了错误
- 503 Service Unavailable:临时停机或维护
401与403之间的区别让许多开发者感到困惑。将401视为“我不知道你是谁”,将403视为“我知道你是谁,但你不能这样做”。这很重要,因为它告诉客户端重新身份验证是否可能有所帮助。
同样,400与422之间的区别是微妙但有用的。对于格式错误的JSON或缺失的必填字段——那些未能解析的基本问题,使用400。对于违反业务逻辑的情况,例如试图转移账户中不存在的资金,使用422。这个区别有助于客户端适当地对错误进行分类。
在我之前的公司,我们实施了正确的状态代码使用,看到与API错误相关的支持票在第一季度下降了67%。开发者终于可以依赖标准的HTTP语义,而不是解析响应体来确定成功或失败。
原则3:从第一天起给您的API进行版本控制(并做到正确)
我通过苦涩的教训学会了这一点。2014年,我发布了一个没有版本控制的API,因为“我们只需永远保持向后兼容”。六个月后,我们需要进行破坏性的更改以支持一个关键的业务需求。我们有1,200个活跃的API消费者,却无法逐步迁移。结果是迫使升级,导致了许多用户困扰。