原文:REST API Design Best Practices,本文内容为笔者翻译以及自我理解的分享。
设计 API 应该:
/items
,/books
/createItems
, /getBooks
/book
和 /books
/customers/{id}/orders
/users/123/posts/456/comments/789/likes
,此类难以看出资源之间的关系/v1/book
和 /v2/book
?version=2
/items?lastItemId=1000&limit=20
/users?lastName=Smith&age=30
/products?fields=id,name,price
(从数据库中读取少量数据,高效)/posts?sort=+author,-datePublished
注:通过 URL 传输查询参数的方案不够方便,一来 URL 长度有限(依然够长,小问题),二来更重要的是查询参数的类型需要额外的机制去统一序列化,通常前端的数字通过此方式传输到接口层,后端需要处理字符串类型。相对通过 JSON Payload 传输需要额外的统一的序列化机制支持
DELETE
和 PUT
操作尤为重要。202
表示操作已被接受但尚未完成。GET /orders/123/status
。Location
头部中包含状态端点的URL,帮助客户端了解操作状态的获取位置。这遵循了HATEOAS原则(超媒体作为应用状态的引擎),即API应告知客户端下一步可以做什么。DELETE /orders/123/cancel
。HEAD
请求检查资源大小,然后使用 Range
头部请求特定的分块。(不错的技巧,检测资源而不需要获取资源)204
。(通常后端会返回 200 😂)题外话,我曾经思考过前端请求中的拦截器在返回响应数据之前应该如何处理服务端状态码。 我认为应该统一使用规范的状态码,避免使用自定义状态码(在返回的 JSON 中定义 status code)。 在某次群组讨论中,有人提出应该在拦截器中既处理常规服务端异常状态码,也要在应用的返回 JSON 中提供应用级别的状态码。
转移一下话题,让 AI 来分析一下第二种做法:在 HTTP 响应中使用标准的 HTTP 状态码,同时在响应体中提供应用级状态码(如 data.code)有几个明显的好处:
1. 分离关注点,增强灵活性
• HTTP 状态码负责协议级别的错误处理,例如,网络错误、未授权、服务器错误等,这些问题通常与请求的传输和处理过程有关。而 应用级状态码(如 data.code**)则专注于应用逻辑层的状态**,比如操作成功、数据验证失败、权限不足等。
• 通过分离这两者,你可以在 HTTP 协议层面保持标准化,同时在应用层提供更细粒度的控制。这使得前端能更精确地响应不同的应用级别错误,而不至于因为协议层的状态码而混淆业务逻辑。
2. 清晰的错误处理
• 使用标准的 HTTP 状态码可以保证大多数情况都能通过简单的检查处理。例如,4xx 状态码就能快速告诉你是否是客户端请求错误,5xx 则提示服务器故障。
• 但对于更复杂的错误或业务逻辑层的错误,应用级状态码可以提供更多信息,如表单字段错误、用户权限问题、请求失败的具体原因等。前端可以通过这些状态码精准控制显示错误信息或者执行相应的操作,而不必依赖于模糊的 HTTP 状态码。
3. 提升可扩展性
• 如果你的应用有较复杂的业务逻辑,使用标准的 HTTP 状态码可能无法涵盖所有业务场景。比如,一个登录接口可能返回 200 状态码,但需要根据 data.code 来判断是登录成功还是账号被锁定。
• 应用级状态码使得你能够定义更加细化的业务逻辑处理流程。随着应用规模增长,增加新的应用级状态码也会变得更加清晰和有序。
4. 用户体验的优化
• 前端可以通过 data.code 做出非常细粒度的用户提示和引导,避免过度依赖 HTTP 状态码。例如: • 200 状态码表示请求成功,但可以通过 data.code 判断是否需要用户做出进一步操作(如修改某些字段)。 • 401 状态码表示未授权,但 data.code 可能告诉用户“您的账户已过期”或“您的权限不足”。 • 这种细节上的处理能极大地提升用户体验,减少因信息不充分而导致的困惑。
5. 便于国际化与本地化
• 通过应用级状态码返回的错误信息可以与用户语言和地区相关联。你可以根据 data.code 和对应的消息字段来返回本地化的错误信息,而无需依赖 HTTP 状态码本身。
• 这种方式也能让你方便地为用户提供定制化的解决方案,例如,依据 data.code 提供不同的帮助文档链接或者操作指南。
6. 可调试性和日志记录
• 使用应用级状态码可以让开发者在日志中记录更具体的错误信息,有助于定位和排查问题。比如,可以在日志中明确标记是由于数据验证失败、权限问题还是某个特定业务条件未达成而导致的错误。
这样,你不仅能在后端更好地跟踪错误发生的原因,也能在前端做针对性的调试和处理。
我被说服了。
文档是重中之重,提供设计文档甚至优先于提供测试接口
HATEOAS (Hypermedia as the Engine of Application State) 是一种 RESTful API 的设计理念,它是 REST 架构风格的一个重要特性之一。HATEOAS 强调“超媒体作为应用程序状态的引擎”,也就是说,客户端不仅能获取资源的数据,还能通过从资源响应中获得的超链接来进一步了解该资源及其操作。
HATEOAS 主要是通过返回动态生成的超链接(links)来引导客户端如何进行下一步的操作,而不仅仅是返回数据。客户端通过这些超链接可以根据当前资源状态,知道能够进行哪些操作。
举个例子: 假设我们有一个用户资源,客户端请求一个特定的用户(例如 /users/1),返回的响应可能如下:
{
"id": 1,
"name": "Alice",
"email": "[email protected]",
"links": [
{
"rel": "self",
"href": "/users/1"
},
{
"rel": "update",
"href": "/users/1/update"
},
{
"rel": "delete",
"href": "/users/1/delete"
},
{
"rel": "friends",
"href": "/users/1/friends"
}
]
}
在这个例子中:
• rel 属性描述了链接的关系,告诉客户端该链接所代表的操作是什么。例如,“self”表示获取当前资源的 URL,“update”表示更新用户信息的 URL。
• href 属性提供了实际的 URL,客户端可以根据这些链接进行进一步操作。
😄 长见识了,如上所示:传统的 REST API 可能要求客户端在请求中使用硬编码的 URL,或者客户端自己在多个请求之间维护操作顺序。而 HATEOAS 通过动态链接提供了明确的导航,使得客户端不需要依赖硬编码的 URL 结构。
我喜欢这种概念,非常灵活。
以上就是今天分享的内容,希望大家喜欢。
Bye.