REST as a Foundation of API Design
有些人可能会强烈反对上面提到的 /translate 和其他 JSON 路由是 API 路由。 其他人可能会同意,但也会认为它们是一个设计糟糕的 API。 那么一个精心设计的 API 有什么特点,为什么上面的 JSON 路由不是一个好的 API 路由呢?
你可能听说过 REST API 。 REST(Representational State Transfer)是 Roy Fielding 在 博士论文 中提出的一种架构。 该架构中,Dr. Fielding 以相当抽象和通用的方式展示了 REST 的六个定义特征。
除了 Dr.Fielding 的论文外,没有关于 REST 的权威性规范,从而留下了许多细节供读者解读。 一个给定的 API 是否符合 REST 规范的话题往往是 REST“纯粹主义者”之间激烈争论的源头,REST“纯粹主义者”认为 REST API 必须以非常明确的方式遵循全部六个特征,而不像 REST“实用主义者”那样,仅仅将 Dr. Fielding 在论文中提出的想法作为指导原则或建议。Dr.Fielding 站在纯粹主义阵营的一边,并在博客文章和在线评论中的撰写了一些额外的见解来表达他的愿景。
目前实施的绝大多数 API 都遵循“实用主义”的 REST 实现。 包括来自 Facebook,GitHub,Twitter 等“大玩家”的大部分 API 都是如此。很少有公共 API 被一致认为是纯 REST,因为大多数 API 都没有包含纯粹主义者认为必须实现的某些细节。 尽管 Dr. Fielding 和其他 REST 纯粹主义者对评判一个 API 是否是 REST API 有严格的规定,但软件行业在实际运用中引用 REST 是很常见的。
为了让你了解 REST 论文中的内容,以下各节将介绍 Dr. Fielding 列举的六项原则。
客户端-服务器
客户端-服务器原则相当简单,正如其字面含义,在 REST API 中,客户端和服务器的角色应该明确区分。 在实践中,这意味着客户端和服务器都是单独的进程,并在大多数情况下,使用基于 TCP 网络上的 HTTP 协议进行通信。
分层系统
分层系统原则是说当客户端需要与服务器通信时,它可能最终连接到代理服务器而不是实际的服务器。 因此,对于客户端来说,如果不直接连接到服务器,它发送请求的方式应该没有什么区别,事实上,它甚至可能不知道它是否连接到目标服务器。 同样,这个原则规定服务器兼容直接接收来自代理服务器的请求,所以它绝不能假设连接的另一端一定是客户端。
这是 REST 的一个重要特性,因为能够添加中间节点的这个特性,允许应用程序架构师使用负载均衡器,缓存,代理服务器等来设计满足大量请求的大型复杂网络。
缓存
该原则扩展了分层系统,通过明确指出允许服务器或代理服务器缓存频繁且相同请求的响应内容以提高系统性能。 有一个你可能熟悉的缓存实现:所有 Web 浏览器中的缓存。 Web 浏览器缓存层通常用于避免一遍又一遍地请求相同的文件,例如图像。
为了达到 API 的目的,目标服务器需要通过使用 缓存控制 来指示响应是否可以在代理服务器传回客户端时进行缓存。 请注意,由于安全原因,部署到生产环境的 API 必须使用加密,因此,除非此代理服务器 terminates SSL 连接,或者执行解密和重新加密,否则缓存通常不会在代理服务器中完成。
按需获取客户端代码(Code On Demand)
这是一项可选要求,规定服务器可以提供可执行代码以响应客户端,这样一来,就可以从服务器上获取客户端的新功能。 因为这个原则需要服务器和客户端之间就客户端能够运行的可执行代码类型达成一致,所以这在 API 中很少使用。 你可能会认为服务器可能会返回 JavaScript 代码以供 Web 浏览器客户端执行,但 REST 并非专门针对 Web 浏览器客户端而设计。 例如,如果客户端是 iOS 或 Android 设备,执行 JavaScript 可能会带来一些复杂情况。
无状态
无状态原则是 REST 纯粹主义者和实用主义者之间争论最多的两个中心之一。 它指出,REST API 不应保存客户端发送请求时的任何状态。 这意味着,在 Web 开发中常见的机制都不能在用户浏览应用程序页面时“记住”用户。 在无状态 API 中,每个请求都需要包含服务器需要识别和验证客户端并执行请求的信息。这也意味着服务器无法在数据库或其他存储形式中存储与客户端连接有关的任何数据。
如果你想知道为什么 REST 需要无状态服务器,主要原因是无状态服务器非常容易扩展,你只需在负载均衡器后面运行多个服务器实例即可。 如果服务器存储客户端状态,则事情会变得更复杂,因为你必须弄清楚多个服务器如何访问和更新该状态,或者确保给定客户端始终由同一服务器处理,这样的机制通常称为 粘性会话 。
再思考一下本章介绍中讨论的 /translate 路由,就会发现它不能被视为 RESTful ,因为与该路由相关的视图函数依赖于 Flask-Login 的 @login_required
装饰器, 这会将用户的登录状态存储在 Flask 用户会话中。
统一接口
最后,最重要的,最有争议的,最含糊不清的 REST 原则是统一接口。 Dr. Fielding 列举了 REST 统一接口的四个特性:唯一资源标识符,资源表示,自描述性消息和超媒体。
唯一资源标识符是通过为每个资源分配唯一的 URL 来实现的。 例如,与给定用户关联的 URL 可以是 /api/users/ ,其中是在数据库表主键中分配给用户的标识符。 大多数 API 都能很好地实现这一点。
资源表示的使用意味着当服务器和客户端交换关于资源的信息时,他们必须使用商定的格式。 对于大多数现代 API,JSON 格式用于构建资源表示。 API 可以选择支持多种资源表示格式,并且在这种情况下,HTTP 协议中的 内容协商 选项是客户端和服务器确认格式的机制。
自描述性消息意味着在客户端和服务器之间交换的请求和响应必须包含对方需要的所有信息。 作为一个典型的例子,HTTP 请求方法用于指示客户端希望服务器执行的操作。 GET
请求表示客户想要检索资源信息, POST
请求表示客户想要创建新资源, PUT
或 PATCH
请求定义对现有资源的修改, DELETE
表示删除资源的请求。 目标资源被指定为请求的 URL,并在 HTTP 头,URL 的查询字符串部分或请求主体中提供附加信息。
超媒体需求是最具争议性的,而且很少有 API 实现,而那些实现它的 API 很少以满足 REST 纯粹主义者的方式进行。由于应用程序中的资源都是相互关联的,因此此要求会要求将这些关系包含在资源表示中,以便客户端可以通过遍历关系来发现新资源,这几乎与你在 Web 应用程序中通过点击从一个页面到另一个页面的链接来发现新页面的方式相同。理想情况下,客户端可以输入一个 API,而不需要任何有关其中的资源的信息,就可以简单地通过超媒体链接来了解它们。但是,与 HTML 和 XML 不同,通常用于 API 中资源表示的 JSON 格式没有定义包含链接的标准方式,因此你不得不使用自定义结构,或者类似 JSON-API , HAL , JSON-LD 这样的试图解决这种差距的 JSON 扩展之一。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论