设计 RESTful API 的指南

设计 RESTful API 的指南

本文最初发表于 https://www.learncsdesign.com

统一资源标识符 (URI) 被 REST API 用来识别资源。在这篇文章中,我们将介绍一组 API 设计规则,这些规则由与 Web 的 REST 架构风格一致的最佳实践塑造而成。

URI 格式规则

以下是中描述的通用 URI 语法 RFC 3986

URI = 方案“😕/” 权限“/” 路径 [“?”查询] [“#”片段]

规则 1:必须使用正斜杠分隔符 (/) 来表示层级关系

它必须用于指示资源之间的层次关系。
例如:
** https://api.medium.com/v1/users/learncsdesign/publications**

规则 2:尾随正斜杠 (/) 不应包含在 URI 中

URI 路径中的结尾正斜杠 (/) 不会增加语义值,并且可能会导致混淆。 REST API 不应期待尾部斜杠,也不应将它们包含在它们提供给客户端的链接中。
例如:
** https://api.medium.com/v1/me**

规则 3:应使用连字符 (-) 来提高 URI 的可读性

您可以通过在 URI 中包含连字符 (-) 来提高长路径段的可读性,以使它们更易于扫描和解释。在 URI 中,无论在哪里使用英文空格或连字符,都应该使用连字符。
例如:
** https://api.razorpay.com/v1/payment-links**

规则 4:URI 中不应使用下划线 ()_

URI 通常在浏览器内的应用程序中带有下划线,以表明它们可以被单击。下划线可以部分或完全遮盖下划线 () 字符,具体取决于应用程序的字体。为了避免这种混淆,请使用连字符 (-) 而不是下划线 ()。

规则 5:URI 路径中应优先​​使用小写字母

最好在 URI 路径中使用小写字母,因为大写字母有时会导致问题。 RFC 3986 指定 URI 区分大小写,但它们的方案和主机组件除外。
例如:

  1. https://api.medium.com/v1/users/learncsdesign/publications
  2. https://API.MEDIUM.COM/v1/users/learncsdesign/publications
  3. https://api.medium.com/v1/Users/learncsdesign/publications

根据 URI 格式规范 (RFC 3986),URI 1 和 2 是相同的,但 URI 3 并不相同,因为 U 在 URI 3 的用户中大写,这可能会导致混淆。

规则 6:文件扩展名不应包含在 URI 中

句点 (.) 字符通常用于分隔 Web 上 URI 的文件名和扩展名部分。为了指示消息实体主体的格式,REST API 不应在 URI 中包含人为的文件扩展名。要确定如何处理正文的内容,它们应该依赖于媒体类型,由 ** 内容类型** 标题。

HTTP 客户端使用 ** 接受** 标头指定可接受的响应媒体类型。反过来,服务器将发回一个响应,其中包含 Content-Type 标头,通知客户端返回的媒体类型。

现在 ** 内容类型** 标头也可以在请求和响应中。但为什么?考虑 POST 或 PUT 请求。作为这些请求类型的一部分,客户端实际上正在向服务器发送一堆数据,并且 ** 内容类型** 标头告诉服务器数据是什么以及如何解析它。
例如:
** https://api.medium.com/v1/users/learncsdesign/publication.json** , 这 ** 接受** 应使用请求标头而不是文件扩展名来指示格式偏好。

URI 权威设计

REST API 的权限部分应遵循的命名约定。

URI = 方案“😕/” 权限“/” 路径 [“?”查询] [“#”片段]

规则 1:API 应使用一致的子域名

API 的顶级域和第一个子域应标识服务所有者。 API 应作为子域添加到完整域名。
例如:
** https://api.medium.com**

规则 2:客户端开发者门户应使用一致的子域

许多 REST API 都附带一个开发人员门户,该门户提供文档、论坛和安全 API 密钥的自助服务配置,以帮助新客户入职。按照惯例,开发人员门户应该有一个标记为开发人员的子域。
例如:
** https://developer.android.com**

资源建模

URI 传达 REST API 的资源模型,每个正斜杠分隔的路径段对应于模型中的唯一资源。

例如,
这个 URI 设计: ** https://api.medium.com/v1/users/learncsdesign/publications** ** __** 表示这些 URI 中的每一个也应该标识一个可寻址资源:
** https://api.medium.com/v1/users/learncsdesign**
** https://api.medium.com/v1/users**

规则 1:资源原型

作为对 API 资源建模的起点,我们可以查看一些基本的资源原型。

以下四种原型描述了 REST API 的资源:

  1. 文档 — 文档资源的概念类似于对象实例或数据库记录的概念。文档资源可以具有表示从属概念的子资源。
    例如 - ** https://api.book.com/v1/authors/sam-newman/books/building-microservices** ** _
    _由于它能够将许多不同的资源类型组合为一个,文档是 REST API 根资源的逻辑候选者,称为 ** 文档根 .
    例如 - ** https://api.book.com**
  2. 收藏 — 集合资源是服务器管理的资源目录。客户可以建议将新资源添加到集合中。由集合决定是否创建新资源。每个集合资源决定它将包含什么以及它将包含的资源的 URI。
    例如 - ** https://api.book.com/v1/authors/sam-newman/books**
  3. 店铺 — 商店是客户管理资源的存储库。存储资源允许 API 客户端添加资源、检索它们并决定何时删除它们。商店不会自己创造新资源;因此,它们不会创建新的 URI。相反,每个存储的资源都有一个由客户端在最初添加到存储时创建的唯一 URI。例如 - 一个 id 为 1234 的用户在他/她的收藏夹中添加了一个名为 building-microservices 的图书文档资源。
    ** ** ** https://api.book.com/v1/users/1234/favorite-books/building-microservices**
  4. 控制器 — 控制器资源代表一个过程概念。控制器资源就像函数一样,具有参数、返回值、输入和输出。控制器的名称通常是 URI 路径中的最后一段,层次结构中没有子资源跟随它。
    例如 — 向 id 为 123 的用户发送 SMS
    ** 邮政** ** https://api.book.com/v1/users/123/sms-send**

URI路径设计

Collection 包含 store 和 store 存储文档 {collection}/{store}/{document}

由正斜杠 (/) 分隔的 URI 路径段分别代表一个设计机会。当路径段被赋予有意义的值时,可以清楚地理解 REST API 资源模型的层次结构。

构建有意义的 URI 路径的指南:

规则 1:文档名称的单数名词

表示文档资源的 URI 应使用单数名词命名。
例如——书籍文档的 URI 将具有单数形式
** https://api.book.com/v1/authors/sam-newman/books/{book-name}**

规则 2:集合名称的复数名词

标识集合的 URI 应该使用复数名词。集合的名称应该反映它的统一组成。
例如——书籍文档集合的 URI 使用其包含资源的复数名词形式
** https://api.book.com/v1/authors/sam-newman/books**

规则 3:商店名称的复数名词

标识资源存储的 URI 的名称应包含复数名词。
例如 — ID 为 1234 的用户收藏的图书商店的 URI
** https://api.book.com/v1/users/1234/favorite-books**

规则 4:控制器名称的动词

标识控制器资源的 URI 应附有指示其操作的名称。
例如 - ** https://api.book.com/v1/authors/sam-newman/publish**

规则 5:可变路径段可以替换为基于身份的值

URI 路径段可以有固定的名称,由 REST API 的设计者选择。其他 URI 路径段是可变的,这意味着它们会自动填充一些标识符,这有助于使 URI 具有唯一性。设计人员可以使用 URI 模板语法清楚地命名静态和可变段。 URI 模板包含在解析之前必须替换的变量。
例如 - ** https://api.medium.com/v1/users/{userId}/publications**

规则 6:不应在 URI 中使用 CRUD 函数名称

不应使用 URI 来指示已执行 CRUD 操作。 URI 应该用于标识资源,并且它们的名称应该遵循上述规则。您应该使用 HTTP 请求方法来指示正在执行的 CRUD 功能。
例如:
** 得到 ** https://api.medium.com/v1/me** ** _
邮政_
** https://api.medium.com/v1/users/{authorId}/posts**

URI查询设计

请记住,在 RFC 3986 中,URI 的可选查询出现在路径之后但可选片段之前。

URI = 方案“😕/” 权限“/” 路径 [“?”查询] [“#”片段]

查询有助于将资源的唯一标识作为其 URI 的一部分。

例如:
** https://api.book.com/v1/authors/sam-newman/publications** ** _
_** ** https://api.book.com/v1/authors/sam-newman/publications?rank=newest**

带有查询参数的 URI 会修改发布的顺序,以便在顶部显示最新的发布。

URI 的查询组件包含一组参数,这些参数可以解释为资源的变体或派生,由路径组件分层标识。虽然这两种资源并不相同,但它们密切相关。

规则 1:查询可用于过滤集合或商店

URI 的查询组件使向集合或商店提供搜索条件变得容易。
例如
** 得到 ** https://api.book.com/v1/users**
** 得到
** https://api.book.com/v1/users?role=admin**

第一个 URI 响应包含集合中所有用户的列表,而第二个 URI 响应包含集合中具有管理员角色的所有用户的过滤列表。

规则 2:查询可用于过滤集合或商店

REST API 客户端可以使用 PageSize 和 pageStartIndex 参数对集合结果进行分页。
例如
** 得到** ** https://api.book.com/v1/users?pageSize=10 &pageStartIndex=100**

请求方法

HTTP 方法在 REST API 的资源模型的上下文中具有特定的、定义良好的语义。

  • 得到 检索资源状态的表示。
  • 检索与资源状态关联的元数据。
  • 应该用于向商店添加新资源或更新现有资源。
  • 删除 从其父级移除资源。
  • 邮政 方法应该用于在集合中创建新资源并运行控制器。

规则 1:GET 和 POST 不得用于隧道其他请求方法

隧道是任何掩盖或歪曲消息意图并破坏协议透明度的行为。为了适应 HTTP 词汇量有限的客户端,REST API 不得因滥用 HTTP 请求方法而损害其设计。

规则 2:必须使用 GET 来检索资源的表示

REST API 客户端使用请求消息中的 GET 方法检索资源的状态。来自客户端的 GET 请求消息可能包含标头,但不包含正文。

规则 3:必须使用 PUT 来插入和更新存储的资源

必须使用 PUT 方法和客户端指定的 URI 将资源添加到存储区。 PUT 还必须用于更新或替换现有资源。 PUT 请求消息必须包含客户端想要存储的资源的表示。

规则 4:必须使用 POST 在集合中创建新资源

为了在集合中创建新资源,客户端使用 POST。 POST 请求包含要添加到请求正文中的服务器拥有的集合的新资源的状态表示。

规则 5:必须使用 POST 来执行控制器

面向函数的控制器资源由客户端使用 POST 方法调用。作为控制器资源功能的输入,POST 请求消息可能包括标头和正文。

HTTP 认为 POST 请求是不安全且非幂等的,这意味着其结果是不可预测的,并且不能保证在没有潜在不良副作用的情况下可重复。
例如:
** 邮政** ** https://api.book.com/v1/users/123/sms-send**

规则 6:必须使用 DELETE 从其父资源中删除资源

客户端使用 DELETE 请求从其父级(通常是集合或存储)中删除资源。处理资源的 DELETE 请求后,客户端将无法再找到该资源。因此,任何未来使用 GET 或 HEAD 检索资源状态表示的请求都应导致 API 出现 404(“未找到”)状态。例如:
** 删除** ** https://api.razorpay.com/v1/invoices/inv-DAuFuwWYU3R9tg**

规则 7:应使用 OPTIONS 检索描述资源可用交互的元数据

客户端可以使用 OPTIONS 请求方法来检索资源元数据,其中包括 ** 允许** 标头值。
例如: ** 允许:获取、放置、删除**

响应状态代码

HTTP 定义了标准状态代码,用于传达客户端请求的结果。它们分为五类。

在本节中,我们将描述如何以及何时使用适用于 REST API 设计的代码子集。

规则 1:应使用 200(“OK”)表示成功

它表明 REST API 成功完成了客户端请求的任何操作,并且不需要 2xx 系列中的更多特定代码。与 204 状态代码相比,200 响应必须包含响应正文。

规则 2:200(“OK”)不得用于传达响应正文中的错误

适当使用 HTTP 响应状态码,不应使用 200 响应码来传达响应正文中的错误。

规则 3:必须使用 201(“CREATED”)表示资源创建成功

如果集合或商店应客户端请求添加新资源,则 REST API 将使用 201 状态代码进行响应。作为某些控制器操作的结果,也可能会创建一个新资源,在这种情况下,201 也是正确的响应。

规则 4:必须使用 202(“ACCEPTED”)来指示异步操作的成功启动

202 响应表示将异步处理客户端的请求。根据此响应状态码,客户端的请求看似有效,但处理后仍可能出现问题。它通常用于需要很长时间才能处理的操作。只有控制器资源应该发送 202 响应。

规则 5:当响应正文故意为空时,应使用 204(“NO CONTENT”)

当 REST API 拒绝返回响应消息正文中的任何状态消息或表示时,通常会返回 204 响应代码以响应 PUT、POST 或 DELETE 请求。 204 也可以作为 GET 请求的一部分发送,以指示所请求的资源存在但没有状态表示。

规则 6:应使用 301(“永久移动”)重新定位资源

301 状态代码表明 REST API 的资源模型已经过重大重新设计,并且已将新的永久 URI 分配给客户端请求的资源。在响应的 Location 标头中,REST API 应该指定新的 URI。

规则 7:不应使用 302(“发现”)

HTTP 1.1 标准引入了状态码 303(“See Other”)和 307(“Temporary Redirect”),应该使用它们来代替 302。

规则 8:应使用 303(“SEE OTHER”)将客户端指向不同的 URI

303 响应表示控制器资源已完成其任务,但它不会发送可能不需要的响应正文,而是向客户端发送响应资源的 URI。 REST API 可以使用 303 状态代码发送对资源的引用,而无需强制客户端下载其状态。或者,客户端可以向 Location 标头的值发送 GET 请求。

规则 9:应使用 304(“未修改”)来保留带宽

它与 204(“无内容”)类似,响应正文必须为空。一个关键的区别是,204 用于正文中没有要发送的内容,而 304 用于有与资源相关联的状态信息,但客户端已经拥有该表示的最新版本。

规则 10:应使用 307(“TEMPORARY REDIRECT”)告诉客户端将请求重新提交到另一个 URI

307 响应表示 REST API 不会处理客户端的请求。客户端应将请求重新提交到响应消息的 Location 标头中指定的 URI。

规则 11:400(“BAD REQUEST”)可用于指示非特定失败

当没有其他合适的 4xx 错误代码时,400 用作一般客户端错误状态。

规则 12:当客户端的凭据出现问题时,必须使用 401(“UNAUTHORIZED”)

401 错误响应表示客户端未经授权访问了受保护的资源。客户端可能提供了不正确的凭据或根本没有提供。

规则 13:无论授权状态如何,都应使用 403(“FOBIDDEN”)禁止访问

在 403 响应中,客户端的请求格式正确,但 REST API 拒绝接受它。 403 响应强制执行应用程序级权限。

规则 14:当客户端的 URI 无法映射到资源时,必须使用 404(“NOT FOUND”)

404 错误状态代码表示 REST API 无法将客户端的 URI 映射到资源。

规则 15:不支持 HTTP 方法时必须使用 405(“METHOD NOT ALLOWED”)

API 以 405 错误响应,表明客户端已尝试使用资源不支持的 HTTP 方法。

规则 16:当请求的媒体类型无法提供时,必须使用 406(“NOT ACCEPTABLE”)

根据 Accept 请求标头,406 错误消息表明 API 无法生成任何客户端的首选媒体类型。

规则 17:409(“CONFLICT”)应用于指示违反资源状态

错误 409 表示客户端已尝试将 REST API 的资源更改为不可能或不一致的状态。

规则 18:412(“PRECONDITION FAILED”)应该用于支持条件操作

根据 412 错误响应,客户端在其请求标头中指定了一个或多个前置条件,有效地告诉 REST API 仅在满足某些条件时才执行请求。如果不满足这些条件,API 会使用此状态代码进行响应,而不是执行请求。

规则 19:当无法处理请求负载的媒体类型时,必须使用 415(“不支持的媒体类型”)

415 错误响应表示 API 无法处理客户端提供的媒体类型,如 Content-Type 请求标头所示。

规则 20:应使用 500(“INTERNAL SERVER ERROR”)表示 API 故障

通用 REST API 错误代码是 500。大多数 Web 框架使用此响应状态代码来响应任何引发异常的请求处理程序。

HTTP 标头

HTTP 的请求和响应消息可能包含传达不同类型元数据的实体标头。 REST API 设计者可以使用这些规则来处理 HTTP 的标准标头。

规则 1:必须使用 Content-Type

Content-Type 描述了可以在请求或响应消息的正文中找到的数据类型。此标头的值是一种特殊类型的字符串,称为媒体类型。客户端和服务器使用此标头的值来确定如何处理消息正文中的字节序列。

规则 2:必须使用 Content-Length

Content-Length 标头指示实体主体的大小(以字节为单位)。此标头很重要,原因有两个。首先,客户端可以确定它是否从连接中读取了正确数量的字节。此外,客户端可以发出 HEAD 请求来确定实体主体的大小,而无需下载它。

规则 3:应在响应中使用 Last-Modified

只有响应消息包含 Last-Modified 标头。此响应标头包含一个时间戳,指示资源的表示状态上次更改的时间。客户端和缓存中介可以使用此标头来确定资源状态表示的本地副本的新鲜度。响应 GET 请求时,应始终包含此标头。

规则 4:应在响应中使用 ETag

该值是一个不透明的字符串,用于标识响应实体中包含的表示状态的特定“版本”。 HTTP 消息的有效负载由消息的标头和正文组成。实体标签可以是任何字符串值,只要它们随资源表示而改变。始终发送此标头以响应 GET 请求。客户端可以存储 ETag 标头的值以供将来 GET 请求使用,作为条件 If-None-Match 请求标头的值。如果 REST API 确定实体标签未更改,则它可以通过不再发送表示来节省时间和带宽。

规则 5:商店必须支持有条件的 PUT 请求

可以使用 PUT 方法更新和插入存储资源,因此 REST API 很难确定客户端 PUT 请求的真实意图。使用 HTTP 标头,API 能够解决可能出现的任何歧义。为了表达他们的意图,REST API 必须依赖客户端来包含 If-Unmodified-Since 和/或 If-Match 请求标头。当指定 If-Unmodified-Since 请求标头时,仅当且仅当资源的状态表示自标头指定的时间以来未更改时,才请求 API 继续操作。 If-Match 包含一个实体标记,客户端从早期响应的 ETag 标头中记住该标记。使用 If-Match 标头,请求是有条件的,取决于标头的实体标记值是否与表示状态的当前实体标记值匹配,由 REST API 存储或计算。

规则 6:必须使用 Location 来指定新创建资源的 URI

Location 响应标头包含客户端可能觉得有用的资源的 URL。在集合或存储中创建资源时,REST API 必须包含 Location 标头以标识新创建资源的 URI。

规则 7:应该使用 Cache-Control、Expires 和 Date 响应标头来鼓励缓存

HTTP 最有用的特性之一是缓存。包含一个 Cache-Control 标头,其 max-age 值(以秒为单位)等于提供表示时的新鲜持续时间。为了支持 HTTP 1.0 缓存,REST API 应该包含一个带有过期日期时间的 Expires 标头。该值是 API 生成表示的时间加上新鲜度的生命周期。 REST API 还应该包含一个 Date 标头,其中包含 API 返回响应的时间。通过包含此标头,客户端可以将新鲜度生命周期计算为 Expires 和 Date 标头的值之间的差异。

规则 8:Cache-Control、Expires 和 Pragma 响应标头可用于阻止缓存

如果不应缓存 REST API 响应,请添加值为 no-cache 和 no-store 的 Cache-Control 标头。为了与旧的 HTTP 1.0 缓存兼容,您还应该添加 Pragma: no-cache 和 Expires: 0 标头值。

规则 9:应鼓励缓存

no-cache 指令阻止任何缓存提供缓存响应。除非绝对必要,否则 API 不应这样做。而不是添加一个 no-cache 指令,一个小的 max-age 值可以帮助客户端至少在短时间内检索缓存的副本,而不会显着影响新鲜度。

规则 10:过期缓存标头应与 200(“OK”)响应一起使用

为了响应成功的 GET 和 HEAD 请求,设置过期缓存标头。尽管 POST 是可缓存的,但大多数缓存并不缓存此方法。您不必为其他方法设置过期标头。

规则 11:过期缓存标头可以选择与 3xx 和 4xx 响应一起使用

除了使用 200(“OK”)响应代码的成功响应之外,请考虑缓存 3xx 和 4xx 响应的标头。它减少了 REST API 上的重定向和错误触发负载量,称为负缓存。

规则 12:不得使用自定义 HTTP 标头来更改 HTTP 方法的行为

自定义标题只能用于信息目的。确保客户端和服务器在找不到预期的自定义标头时不会失败。当您通过自定义 HTTP 标头传达的信息对于正确解释请求或响应至关重要时,将该信息放在请求或响应的正文或请求的 URI 中。传达此类信息时不要使用自定义标题。

如果你喜欢这篇文章,别忘了鼓掌。如果你想连接,你可以找到我 领英 .

参考

REST API 设计规则手册 — Mark H. Massé
RESTful Web APIs — Leonard Richardson & Mike Amundsen

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明

本文链接:https://www.qanswer.top/39360/38582611

posted @ 2022-09-26 11:39  哈哈哈来了啊啊啊  阅读(147)  评论(0编辑  收藏  举报