编写令人惊叹的 REST API 的艺术


在编写 API 时,REST(代表性状态传输的缩写)被视为标准。然而,REST 本身实际上并不是一个标准。这使得设计直观的 REST API 变得非常棘手。它是一种思维方式或艺术形式,而不是清单。

一致性!
如果你在整个界面上保持相同的范式,学习起来就会容易得多。

一致性从大的方面延伸到小的方面,比如你如何划分你的资源,比如你如何命名事物。

除此之外,与你的开发者常用的其他API保持一致也很有用。
如果开发者已经熟悉了一种API,他们就会更快地学习类似的API。

幸运的是,对于我们所有编写API的人来说,这种对一致性的渴望意味着我们可以创建一个检查表或标准。
不幸的是,即使有一个极其全面的标准,边缘案例和奇怪的情况总是会出现。

一切都与资源有关
REST API 以资源为中心。REST 背后的整个概念是您将资源公开给网络。您提供对一组资源的操作。这些资源在您的 API 中应该是完全稳定的。

唯一可能返回完整资源以外的东西的情况是关系:例如,一个资源包含对另一个资源的引用(比如,它有一个父对象)。在这种情况下,可以接受引用资源的最小表示。

这在多服务架构中尤其可取,其中 API 服务可能不拥有引用的所有其他资源,因此应该只负责返回自己的数据。这个最小表示应该包含提取完整资源所需的信息(通常是两个字段:type 和 id)。

在设计这些资源时,请记住您的 API 资源不需要与数据库中的对象相匹配。将其视为以有意义的方式重新设计数据的机会。

ID 和类型让世界运转
在您的 API 上使用唯一 ID。

所有 GET 端点都应该有一个通过 ID 获取的选项。

此 ID 不必是数据库 ID — 它可以包含多个字段并将它们组合或散列在一起。实际上,只要能唯一标识一个对象。

您应该始终在资源中返回一个类型字段,你的资源应该总是有相同的领域。这也延伸到类型。始终包含类型比不包含类型更容易,因为它本来可以带来所有不同。

资源名称很重要
名称应该准确、清楚地阐明资源代表什么。

应该始终是复数名词。资源是对象,所以它们应该始终是名词,因为对象是名词,而不是动词。

为什么是复数?我的想法是资源端点不代表资源的单个实例。相反,它引用您服务器上所有该资源类型的池。

例如:

  • 端点 /plants 代表服务器上的所有植物
  • GET /plants 应该返回这些植物的列表。
  • POST /plants 向该植物池添加一个项目——我正在向植物添加一些东西。
  • 即使在 GET /plants/{plantId} 的情况下,它预计只会返回一个项目(因为唯一的 ID,还记得吗?),它正在将所有植物的列表缩小到一个特定的植物。

因此,资源应该始终是复数名词。同样,我可以执行 /plants?flower_color=blue,它应该返回所有开蓝色花的植物的列表。


遵循相关标准
虽然 REST 没有标准,但它确实使用了一些其他有标准的协议。例如,大多数人使用 JSON 和 HTTP 编写他们的 REST API。这些都不是必需的,但两者,尤其是 HTTP,几乎是通用的。

状态码的正确使用和 HTTP 方法的正确使用。


完整性
如果您实现了 HATEAOS(超媒体作为应用程序状态引擎)链接,人们通常认为它是下一个 REST 级别或真正的 RESTful。也就是说,HATEAOS 链接虽然在概念上很酷,但对于大多数人使用现代 API 的方式没有用处。

因此,在几乎所有情况下,我都建议不要实施它们。

HATEAOS 的主要思想是创建一种遍历 API 的方法,除了起点之外,无需对该 API 有任何先验知识。每个响应都包含指向相关资源等的链接。

我认为 HATEAOS 链接没有用,因为几乎所有根据您的 API 构建的合理人员都会查看您的文档。

应该确保用户可以从一个资源遍历到另一个资源。他们应该能够仅通过 API 完成工作流程。
如果我在我的文件资源中引用父文件夹,我还应该有一个 GET 端点来获取该父文件夹。这重申了 ID 的重要性。如果我列出与用户关联的组,我不应该只列出组名;我应该包括 ID,以便 API 用户可以获得有关这些组的更多信息或操作这些组。他们应该能够遍历从一个资源到另一个资源的数据。

API 的部分优点在于它们开辟了原始公司从未想过的功能可能性。它们允许开发人员将功能扩展到 UI 中提供的用例之外,并创建全新的流程。考虑到这一点,不要只为您了解的用例填写 API,而是尝试从核心对象开始填写尽可能多的 API。