RESTful API 设计最佳实践
时间:2026-01-17
时间:2026-01-17
RESTful API 设计最佳实践
数据模型已经稳定,接下来你可能需要为web(网站)应用创建一个公开的API(应用程序编程接口)。需要认识到这样一个问题:一旦API发布后,就很难对它做很大的改动并且保持像先前一样的正确性。现在,网络上有很多关于API设计的思路。但是在全部案例中没有一种被广泛采纳的标准,有很多的选择:你接受什么样的格式?如何认证?API应该被版本化吗?
在为SupportFu(一个轻量级的Zendesk替换实现)设计API时,对于这些问题我尽量得出一些务实的答案。我的目标是设计这样一个API,它容易使用和采纳,足够灵活去为我们用户接口去埋单。
API的关键要求
许多网上能找到的API设计观点都是些学术讨论,这些讨论是关于模糊标准的主观解释,而不是关于在现实世界中具有意义的事。本文中我的目标是,描述一下为当今的web应用而设计的实用的API的最佳实践。如果感觉不对,我不会去尝试满足某个标准。为了帮助进行决策,我已经写下了API必须力争满足的一些要求:
它应当在需要的地方使用 web 标准
它应当对开发者友好并且便于在浏览器地址栏中浏览和探索
它应当是简单、直观和一致的,使它用起来方便和舒适
它应当提供足够的灵活性来增强大多数的 SupportFu 用户界面
它应当是高效的,同时要维持和其他需求之间的平衡
一个 API 是一个开发者的 UI 就像其他任何 UI 一样, 确保用户体验被认真的考虑过是很重要的!
使用 RESTful URLs and actions
如果有一样东西获得广泛认可的话,那就是 RESTful 原则。Roy Felding 在他论文 network based software architectures 的 第五章 中首次介绍了这些原则。
这些REST的关键原则与将你的 API 分割成逻辑资源紧密相关。使用HTTP请求控制这些资源,其中,这些方法(GET, POST, PUT,PATCH, DELETE)具有特殊含义。
可是我该整出什么样的资源呢?好吧,它们应该是有意义于 API 使用者的名词(不是动词)。虽然内部Model可以简单地映射到资源上,但那不一定是个一对一的映射。这里的关键是不要泄漏与API不相关的实现细节。一些相关的名词可以是 票,用户和小组。
一旦定义好了资源, 需要确定什么样的 actions 应用它们,这些 actions 怎么映射到你的 API 上。RESTful 原则提供了 HTTP methods 映射作为策略来处理 CRUDactions,如下:
GET /tickets 获取 tickets 列表GET /tickets/12 获取一个单独的 ticketPOST /tickets 创建一个新的 ticketPUT /tickets/12 更新 ticket #12PATCH /tickets/12 部分更新 ticket #12DELETE /tickets/12 删除 ticket #12
REST 非常棒的是,利用现有的 HTTP 方法在单个的 /tickets 接入点上实现了显著的功能。没有什么方法命名约定需要去遵循,URL 结构是整洁干净的。 REST 太棒了!
接入点的名称应该选择单数还是复数呢?keepitsimple原则可以在此应用。虽然你内在的语法知识会告诉你用复数形式描述单一资源实例是错误的,但实用主义的答案是保持URL格式一致并且始终使用复数形式。不用处理各种奇形怪状的复数形式(比如person/people,goose/geese)可以让API消费者的生活更加美好,也让API提供者更容易实现API(因为大多数现代框架天然地将/tickets和/tickets/12放在同一个控制器下处理)。
但是你该如何处理(资源的)关系呢?如果关系依托于另外一个资源,Restful原则提供了很好的指导原则。让我们来看一个例子。SupportFu的一个ticket包含许多消息(message)。这些消息逻辑上与/tickets接入点的映射关系如下:
GET /tickets/12/messages 获取ticket #12下的消息列表
GET /tickets/12/messages/5 获取ticket #12下的编号为5的消息
POST /tickets/12/messages 为ticket #12创建一个新消息
PUT /tickets/12/messages/5 更新ticket #12下的编号为5的消息
PATCH /tickets/12/messages/5 部分更新ticket #12下的编号为5的消息
DELETE /tickets/12/messages/5 删除ticket #12下的编号为5的消息
或者如果某种关系不依赖于资源,那么在资源的输出表示中只包含一个标识符是有意义的。API消费者然后除了请求资源所在的接入点外,还得再请求一次关系所在的接入点。但是如果一般情况关系和资源一起被请求,API可以提供自动嵌套关系表示到资源表示中,这样可以防止两次请求API。
如果Action不符合CRUD操作那该怎么办?
这是一个可能让人感到模糊不解的地方。有几种处理方法:
1. 重新构造这个Action,使得它像一个资源的field(我理解为部分域或者部分字段)。这种方法在Action不包含参数的情况下可以奏效。例如一个有效的action
可以映射成布尔类型field,并且可以通过PATCH更新资源。
2. 利用RESTful原则像处理子资源一样处理它。例如,Github的API让你通过 …… 此处隐藏:11012字,全部文档内容请下载后查看。喜欢就下载吧 ……