Google AIP
AIP (API Improvement Proposals) 是总结 Google API 设计决策的设计文档。
这里提供了一些常用文档的翻译。
AIP-1 AIP 目的和指南
随着谷歌 API 语料库的发展,以及 API 治理团队的壮大,以满足支持它们的需求,越来越有必要为 API 生产者、审查者和其他相关方提供文档语料库以供参考。API 风格指南和介绍性的 One Platform 文档有意简洁而高级。AIP 集合提供了一种为 API 设计指南提供一致文档的方法。
AIP-131 标准方法:获取(Standard methods: Get)
在 REST API 中,为了检索资源,通常会向资源的 URI(例如 /v1/publisher/{publisher}/books/{book})发出 GET 请求。
面向资源的设计(AIP-121)通过 Get 方法来尊重这种模式。这些 RPC 接受表示该资源的 URI 并返回该资源。
指导
API 必须为资源提供一个 get 方法。get 方法的目的是从单个资源返回数据。
Get 方法是使用以下模式指定的:
| |
- RPC 的名称必须以
Get一词开头。RPC 名称的其余部分应该是资源消息名称的单数形式。 - 请求消息必须与 RPC 名称匹配,并带有
Request后缀。 - 响应消息必须是资源本身。(没有
GetBookResponse。)- 响应通常应包括完全填充的资源,除非有理由返回部分响应(见 AIP-157)。
- HTTP 谓词必须是
GET。 - URI 应该包含与资源名称相对应的单个变量字段。
- 此字段应称为
name。 - URI 应该有一个与此字段相对应的变量。
name字段应该是 URI 路径中唯一的变量。所有剩余的参数都应该映射到 URI 查询参数。
- 此字段应称为
google.api.http注解中不能有body键。- 应该只有一个值为
"name"的google.api.method_signature注解。
请求消息
Get 方法实现了一个通用的请求消息模式:
| |
- 必须包含资源名称字段。它应该被称为 name。
name字段的注释应该记录资源模式。- 请求消息不得包含任何其他必需字段,也不应包含除其他 AIP 中描述的字段之外的其他可选字段。
name 字段对应于 RPC 上 google.api.http 注解中的 name 变量。因为在使用 REST/JSON 接口时,根据 URL 中的值填充 request 中的 name 字段。错误
请参阅errors,特别是何时使用 PERMISSION_DENIED 和 NOT_FOUND 错误。
Changelog
- 2023-03-17: Align with AIP-122 and make Get a must.
- 2022-11-04: Aggregated error guidance to AIP-193.
- 2022-06-02: Changed suffix descriptions to eliminate superfluous “-”.
- 2020-06-08: Added guidance on returning the full resource.
- 2019-10-18: Added guidance on annotations.
- 2019-08-12: Added guidance for error cases.
- 2019-08-01: Changed the examples from “shelves” to “publishers”, to present a better example of resource ownership.
- 2019-05-29: Added an explicit prohibition on arbitrary fields in standard methods.
AIP-132 标准方法:列表(Standard methods: List)
在许多 API 中,通常会向集合的 URI(例如 /v1/publisher/1/books)发出 GET 请求,以便检索资源列表,每个资源都位于该集合中。
面向资源的设计(AIP-121)通过 List 方法来尊重这种模式。这些 RPC 接受父集合(可能还有一些其他参数),并返回与该输入匹配的响应列表。
指导
API 必须为资源提供 List 方法,除非资源是单例。List 方法的目的是从有限集合返回数据(通常是单个集合,除非操作支持跨集合读取)。
List 方法是使用以下模式指定的:
| |
- RPC 的名称必须以单词
List开头。RPC 名称的其余部分应该是所列资源的复数形式。 - 请求和响应消息必须与 RPC 名称匹配,并带有
Request和Response后缀。 - HTTP 谓词必须是
GET。 - 列出其资源的集合应该映射到 URI 路径。
- 集合的父资源应称为
parent,并且应是 URI 路径中唯一的变量。所有剩余的参数都应该映射到 URI 查询参数。 - 集合标识符(上例中的 books)必须是一个文本字符串。
- 集合的父资源应称为
google.api.http注解中的body键必须省略。- 如果列出的资源不是顶级资源,那么应该只有一个值为
"parent"的google.api.method_signature注解。如果列出的资源是顶级资源,则应该没有google.api.method_signature注解,或者只有一个值为""的google.api.method_signature注解。
请求消息
List 方法实现了一种常见的请求消息模式:
| |
- 除非列出的资源是顶级资源,否则必须包括
parent字段。它应该被称为parent。 - 必须在所有列表请求消息上指定支持分页的
page_size和page_token字段。有关更多信息,请参阅 AIP-158。page_size字段上方的注释应记录允许的最大值,以及省略(或设置为0)字段时的默认值。如果首选 (If preferred),API 可以声明服务器将使用合理的默认值。此默认值可会随着时间的推移而更改。- 如果用户提供的值大于允许的最大值,则 API 应将该值强制为允许的最大。
- 如果用户提供了负值或其他无效值,则 API 必须返回
INVALID_ARGUMENT错误。
page_token字段必须包含在所有列表请求消息中。- 请求消息可以包括与列表方法相关的常见设计模式的字段,例如
string filter和string order_by。 - 请求消息不得包含任何其他必需字段,也不应包含除本 AIP 或其他 AIP 中描述的字段之外的其他可选字段。
响应消息
List 方法实现了一个通用的响应消息模式:
| |
- 响应消息必须包括一个与返回的资源相对应的重复字段,并且不应包括任何其他重复字段,除非在另一个 AIP(例如,AIP-217)中描述。
- 响应通常应包括完全填充的资源,除非有理由返回部分响应(见 AIP-157)。
- 支持分页的
next_page_token字段必须包含在所有列表响应消息中。如果有后续页面,则必须设置它,如果响应表示最终页面,则不得设置它。有关更多信息,请参阅 AIP-158。 - 该消息可以包括具有集合中的项数的
int32 total_size(或int64 total_size)字段。- 该值可以是一个估计值(如果是的话,字段应该清楚地记录在文档中)。
- 如果使用筛选,则
total_size字段应反映应用筛选后集合的大小。
排序
List 方法可以允许客户端指定排序顺序;如果他们这样做了,那么请求消息应该包含一个 string order_by 字段。
- 值应该是以逗号分隔的字段列表。例如:
"foo,bar"。 - 默认的排序顺序是升序。为了指定字段的降序,用户会附加一个
" desc"后缀;例如:"foo desc, bar"。 - 语法中多余的空格字符是无关紧要的。
"foo, bar desc"、" foo , bar desc "和"foo,bar desc"都是等价的。 - 子字段是用指定的。字符,例如
foo.bar或address.street。
过滤
List 方法可以允许客户端指定筛选器;如果他们这样做了,那么请求消息应该包含一个 string filter 字段。过滤在 AIP-160 中有更详细的描述。
软删除的资源
一些 API 需要“软删除”资源,将其标记为已删除或待删除(并可选择稍后清除)。
默认情况下,执行此操作的 API 不应在列表请求中包括已删除的资源。具有软删除资源的 API 应在列表请求中包括一个 bool show_deleted 字段,如果设置该字段,将导致软删除的资源被包括在内。
错误
请参阅errors,特别是何时使用 PERMISSION_DENIED 和 NOT_FOUND 错误。
延伸阅读
Changelog
- 2023-03-22: Fix guidance wording to mention AIP-159.
- 2023-03-17: Align with AIP-122 and make Get a must.
- 2022-11-04: Aggregated error guidance to AIP-193.
- 2022-06-02: Changed suffix descriptions to eliminate superfluous “-”.
- 2020-09-02: Add link to the filtering AIP.
- 2020-08-14: Added error guidance for permission denied cases.
- 2020-06-08: Added guidance on returning the full resource.
- 2020-05-19: Removed requirement to document ordering behavior.
- 2020-04-15: Added guidance on List permissions.
- 2019-10-18: Added guidance on annotations.
- 2019-08-01: Changed the examples from “shelves” to “publishers”, to present a better example of resource ownership.
- 2019-07-30: Added guidance about documenting the ordering behavior.
- 2019-05-29: Added an explicit prohibition on arbitrary fields in standard methods.
AIP-133 标准方法:创建(Standard methods: Create)
在 REST API 中,通常会向集合的 URI(例如 /v1/publisher/{publisher}/books)发出 POST 请求,以便在该集合中创建新的资源。
面向资源的设计(AIP-121)通过 Create 方法来尊重这种模式。这些 RPC 接受父集合和要创建的资源(可能还有一些其他参数),并返回创建的资源。
指导
API 通常应该为资源提供一个创建方法,除非这样做对用户来说没有价值。创建方法的目的是在已经存在的集合中创建一个新的资源。
Create 方法是使用以下模式指定的:
| |
- RPC 的名称必须以
Create一词开头。RPC 名称的其余部分应该是正在创建的资源的单数形式。 - 请求消息必须与 RPC 名称匹配,并带有
Request后缀。 - 响应消息必须是资源本身。没有
CreateBookResponse。- 响应应包括完全填充的资源,并且必须包括所提供的任何字段,除非它们仅是输入的(见 AIP-203)。
- 如果创建 RPC 是长时间运行的,则响应消息必须是解析为资源本身的
google.longrunning.Operation。
- HTTP 谓词必须是
POST。 - 添加资源的集合应该映射到 URI 路径。
- 集合的父资源应称为
parent,并且应是 URI 路径中唯一的变量。 - 集合标识符(上例中的
books)必须是一个文本字符串。
- 集合的父资源应称为
google.api.http注解中必须有一个body键,并且它必须映射到请求消息中的资源字段。- 所有剩余的字段都应该映射到 URI 查询参数。
- 应该只有一个
google.api.method_signature注解,如果要创建的资源不是顶级资源,则其值为"parent,{resource}",如果正在创建的资源是顶级资源(除非该方法支持用户指定的 ID),则该注解的值为"{resource}"。
请求消息
Create 方法实现一个通用的请求消息模式:
| |
- 除非正在创建的资源是顶级资源,否则必须包括
parent字段。它应该被称为parent。 - 资源字段必须包含在内,并且必须映射到 POST body。
- 请求消息不得包含任何其他必需字段,也不应包含除本 AIP 或其他 AIP 中描述的字段之外的其他可选字段。
长时间运行的创建(Long-running create)
有些资源创建资源所花费的时间比常规 API 请求所需的时间更长。在这种情况下,API 应该使用长时间运行的操作(AIP-151):
| |
- 响应类型必须设置为资源(如果 RPC 不是长时间运行的,则返回类型是什么)。
- 必须同时指定
response_type和metadata_type字段。
用户指定的 ID
有时,API 需要允许客户端在创建时指定资源的 ID 组件(资源名称的最后一段)。如果允许用户选择其资源名称的这一部分,这是很常见的。
例如:
| |
创建 RPC 可以通过在请求消息上提供字符串 {resource}_id 字段来支持此行为:
| |
{resource}_id字段必须存在于请求消息中,而不是资源本身。- 该字段可以是必需的,也可以是可选的。如果是必需的,它应该包括相应的注释。
- 必须忽略资源上的
name字段。 - RPC 上应该只有一个
google.api.method_signature注解,如果正在创建的资源不是顶级资源,则其值为"parent,{resource},{resource}_id";如果要创建的资源是顶级资源,其值应为"{resource},{resource}_id"。 - 文档应解释什么是可接受的格式,并且该格式应遵循 AIP-122 中的资源名称格式指南。
- 如果用户试图创建一个 ID 会导致资源名称重复的资源,则该服务必须返回
ALREADY_EXISTS错误。- 但是,如果进行调用的用户没有查看重复资源的权限,则服务必须改为使用
PERMISSION_DENIED。
- 但是,如果进行调用的用户没有查看重复资源的权限,则服务必须改为使用
{resource}_id 作为请求 URI 上的查询参数提供。错误
请参阅errors,特别是何时使用 PERMISSION_DENIED 和 NOT_FOUND 错误。
延伸阅读
Changelog
- 2022-11-04: Referencing aggregated error guidance in AIP-193, similar to other CRUDL AIPs.
- 2022-06-02: Changed suffix descriptions to eliminate superfluous “-”.
- 2020-10-06: Added declarative-friendly guidance.
- 2020-08-14: Updated error guidance to use permission denied over forbidden.
- 2020-06-08: Added guidance on returning the full resource.
- 2019-11-22: Added clarification on what error to use if a duplicate name is sent.
- 2019-10-18: Added guidance on annotations.
- 2019-08-01: Changed the examples from “shelves” to “publishers”, to present a better example of resource ownership.
- 2019-06-10: Added guidance for long-running create.
- 2019-05-29: Added an explicit prohibition on arbitrary fields in standard methods.
AIP-134 标准方法:更新(Standard methods: Update)
在 REST API 中,通常对资源的 URI(例如 /v1/publisher/{publisher}/books/{book})发出 PATCH 或 PUT 请求,以更新该资源。
面向资源的设计(AIP-121)通过 Update 方法(反映 REST PATCH 行为)来尊重这种模式。这些 RPC 接受表示该资源的 URI 并返回该资源。
指导
API 通常应该为资源提供更新方法,除非这样做对用户没有价值。更新方法的目的是在不造成副作用的情况下对资源进行更改。
Update 方法是使用以下模式指定的:
| |
- RPC 的名称必须以单词
Update开头。RPC 名称的其余部分应该是资源消息名称的单数形式。 - 请求消息必须与 RPC 名称匹配,并带有
Request后缀。 - 响应消息必须是资源本身。(没有
UpdateBookResponse。) - 该方法应该支持部分资源更新,HTTP 谓词应该是
PATCH。- 如果该方法只支持完全资源替换,那么 HTTP 谓词可以是
PUT。然而,强烈反对这样做,因为向资源中添加字段会成为向后不兼容的更改。
- 如果该方法只支持完全资源替换,那么 HTTP 谓词可以是
- 资源的
name字段应该映射到 URI 路径。{resource}.name字段应该是 URI 路径中的唯一变量。
google.api.http注解中必须有一个body键,并且它必须映射到请求消息中的 resource 字段。- 所有剩余的字段都应该映射到 URI 查询参数。
- 应该只有一个
google.api.method_signature注解,其值为"{resource},update_mask"。
book.name)。如果资源字段有单词分隔符,则使用 snake_case。请求消息
Update 方法实现了一个通用的请求消息模式:
| |
- 请求消息必须包含资源的字段。
- 如果支持部分资源更新,则必须包含字段掩码。它的类型必须是
google.protobuf.FieldMask,并且应该称为update_mask。- 字段掩码中使用的字段对应于正在更新的资源(而不是请求消息)。
- 该字段可以是必需的,也可以是可选的。如果是必须的,则必须包含相应的注释。如果可选,则服务必须将省略的字段掩码视为隐含字段掩码,该隐含字段掩码等效于填充的所有字段(具有非空值)。
- 更新掩码必须支持一个特殊值
*,这意味着完全替换(相当于PUT)。
- 请求消息不得包含任何其他必需字段,也不应包含除本 AIP 或其他 AIP 中描述的字段之外的其他可选字段。
副作用
通常,更新方法旨在更新资源中的数据。更新方法不应引发其他副作用。相反,副作用应该由自定义方法触发。
特别是,这要求状态字段在更新方法中不能直接写入。
PATCH 和 PUT
PATCH HTTP 谓词,不支持 PUT 请求。我们在 PATCH 上实现了标准化,因为谷歌通过向后兼容的改进来更新稳定的 API。通常有必要向现有资源中添加一个新字段,但在使用 PUT 时,这将成为一个破坏性的更改。
为了说明这一点,考虑对 Book 资源的 PUT 请求:
| |
接下来,考虑资源稍后会添加一个新字段(此处我们添加 rating):
| |
如果对一本书设置了评级,并且执行了现有的 PUT 请求,那么它将清除该书的评级。从本质上讲,PUT 请求无意中擦除了数据,因为以前的版本并不知道这一点。
长时间运行的更新(Long-running update)
某些资源更新资源所需的时间比常规 API 请求所需的合理时间要长。在这种情况下,API 应该使用长时间运行的操作(AIP-151):
| |
- 响应类型必须设置为资源(如果 RPC 不是长时间运行的,则返回类型是什么)。
- 必须同时指定
response_type和metadata_type字段。
创建或更新
如果服务使用客户端分配的资源名称,Update 方法可以暴露一个 bool allow_missing 字段,这将使该方法在用户尝试更新不存在的资源时成功(并将在此过程中创建资源):
| |
更具体地说,allow_missing 标志触发以下行为:
- 如果方法调用所在的资源不存在,则会创建该资源。应用所有字段,而不考虑提供的任何字段掩码。
- 但是,如果缺少任何必需的字段或字段的值无效,则会返回
INVALID_ARGUMENT错误。
- 但是,如果缺少任何必需的字段或字段的值无效,则会返回
- 如果方法调用位于已存在的资源上,并且所有字段都匹配,则返回的现有资源不变。
- 如果方法调用位于已存在的资源上,则只更新字段掩码中声明的字段。
即使 allow_missing 设置为 true,用户也必须具有调用 Update 的更新权限。对于希望阻止用户使用更新方法创建资源的客户,应使用 IAM(Identity and Access Management)条件。
bool allow_missing 字段。Etags
API 有时可能需要允许用户发送更新请求,这些更新请求保证是根据最新数据进行的(这方面的一个常见用例是检测和避免竞争条件)。需要启用此功能的资源通过包含一个 string etag 字段来实现,该字段包含一个不透明的、由服务器计算的值,表示资源的内容。
在这种情况下,资源应该包含一个 string etag 字段:
| |
etag 字段可以是必需的,也可以是可选的。如果设置了它,则只有当且仅当提供的 etag 与服务器计算的值匹配时,请求才能成功,否则必须以 ABORTED 错误失败。请求中的 update_mask 字段不会影响 etag 字段的行为,因为它不是正在更新的字段。
昂贵的字段
API 有时会遇到资源上的某些字段昂贵或无法可靠返回的情况。
这种情况可能发生在几种情况下:
- 资源可能具有一些计算成本非常高的字段,并且这些字段通常对客户的更新请求没有用处。
- 单个资源有时表示来自多个底层(最终是一致的)数据源的数据的合并。在这些情况下,不可能返回未更改字段的权威信息。
在这种情况下,API 可以只返回已更新的字段,而忽略其余字段,如果这样做,则应该记录此行为。
错误
请参阅errors,特别是何时使用 PERMISSION_DENIED 和 NOT_FOUND 错误。
此外,如果用户确实具有适当的权限,但所请求的资源不存在,则除非 allow_missing 设置为 true,否则服务必须出现 NOT_FOUND(HTTP 404)错误
Changelog
- 2022-11-04: Aggregated error guidance to AIP-193.
- 2022-06-02: Changed suffix descriptions to eliminate superfluous “-”.
- 2021-11-04: Changed the permission check if allow_missing is set.
- 2021-07-08: Added error guidance for resource not found case.
- 2021-03-05: Changed the etag error from FAILED_PRECONDITION (which becomes HTTP 400) to ABORTED (409).
- 2020-10-06: Added guidance for declarative-friendly resources.
- 2020-10-06: Added guidance for allow_missing.
- 2020-08-14: Added error guidance for permission denied cases.
- 2020-06-08: Added guidance on returning the full resource.
- 2019-10-18: Added guidance on annotations.
- 2019-09-10: Added a link to the long-running operations AIP.
- 2019-08-01: Changed the examples from “shelves” to “publishers”, to present a better example of resource ownership.
- 2019-06-10: Added guidance for long-running update.
- 2019-05-29: Added an explicit prohibition on arbitrary fields in standard methods.
AIP-135 标准方法:删除(Standard methods: Delete)
在 REST API 中,通常对资源的 URI(例如 /v1/publisher/{publisher}/books/{book})发出 DELETE 请求以删除该资源。
面向资源的设计(AIP-121)通过 Delete 方法来尊重这种模式。这些 RPC 接受表示该资源的 URI,并且通常返回一个空响应。
指导
API 通常应该为资源提供一个删除方法,除非这样做对用户来说没有价值。
Delete 方法是使用以下模式指定的:
| |
- RPC 的名称必须以
Delete一词开头。RPC 名称的其余部分应该是资源消息名称的单数形式。 - 请求消息必须与 RPC 名称匹配,并带有
Request后缀。 - 响应消息应该是
google.protobuf.Empty。 - HTTP 谓词必须是
DELETE。 - 接收资源名称的请求消息字段应该映射到 URI 路径。
- 此字段应称为
name。 name字段应该是 URI 路径中唯一的变量。所有剩余的参数都应该映射到 URI 查询参数。
- 此字段应称为
google.api.http注释中不能有body键。- 应该只有一个值为
"name"的google.api.method_signature注释。如果使用了etag或force field,它们可以包含在签名中。
如果并且仅当资源存在并且已成功删除时,Delete 方法应成功。如果资源不存在,则该方法应返回 NOT_FOUND 错误。
请求消息
Delete 方法实现了一种常见的请求消息模式:
| |
- 必须包含
name字段。它应该被称为name。 - 字段的注释应该记录资源模式。
- 请求消息不得包含任何其他必需字段,也不应包含除本 AIP 或其他 AIP 中描述的字段之外的其他可选字段。
软删除
长时间运行的删除(Long-running delete)
某些资源删除资源所需的时间比常规 API 请求所需的合理时间要长。在这种情况下,API 应该使用长时间运行的操作:
| |
- 如果 RPC 不是长时间运行的,则响应类型必须设置为适当的返回类型:对于大多数 Delete RPC,为
google.protobuf.Empty;对于软删除,为资源本身(AIP-164)。 - 必须同时指定
response_type和metadata_type字段(即使它们是google.protobuf.Empty)。
级联删除
有时,用户可能需要删除资源以及所有适用的子资源。然而,由于删除通常是永久性的,让用户不要意外地删除也很重要,因为重建被删除的子资源可能相当困难。
如果 API 允许删除可能具有子资源的资源,则 API 应在请求上提供 bool force 字段,用户将其设置为明确选择级联删除。
| |
如果 force 字段为 false(或未设置)并且存在子资源,则 API 必须失败,并返回 FAILED_PRECONDITION 错误。
受保护的删除
有时,用户可能需要确保没有对正在删除的资源进行任何更改。如果资源提供了 etag,则删除请求可以接受 etag(作为必须或可选字段):
| |
如果提供的 etag 与服务器计算的 etag 不匹配,则请求必须失败,并返回 ABORTED 错误代码。
etag 字段。删除(如果存在)
如果服务使用客户端分配的资源名称,Delete 方法可以暴露一个 bool allow_missing 字段,这将导致该方法在用户试图删除不存在的资源时成功(在这种情况下,请求是无操作的):
| |
更具体地说,allow_missing 标志触发以下行为:
- 如果方法调用位于不存在的资源上,则请求是无操作的。
etag字段被忽略。
- 如果方法调用位于已存在的资源上,则会删除该资源(接受其他检查)。
bool allow_missing 字段。错误
如果用户没有访问该资源的权限,无论该资源是否存在,该服务都必须返回 PERMISSION_DENIED(HTTP 403)错误。在检查资源是否存在之前,必须检查权限。
如果用户确实具有适当的权限,但所请求的资源不存在,则除非 allow_missing 设置为 true,否则服务必须返回 NOT_FOUND(HTTP 404)错误。
延伸阅读
Changelog
- 2022-06-02: Changed suffix descriptions to eliminate superfluous “-”.
- 2022-02-02: Changed eTag error from
FAILED_PRECONDITIONtoABORTEDmaking it consistent with change to AIP-154 & AIP-134 on 2021-03-05. - 2020-10-06: Added guidance for declarative-friendly resources.
- 2020-10-06: Added guidance for allowing no-op delete for missing resources.
- 2020-10-06: Moved soft delete and undelete guidance into a new AIP-164.
- 2020-06-08: Added guidance for Get of soft-deleted resources.
- 2020-02-03: Added guidance for error cases.
- 2019-10-18: Added guidance on annotations.
- 2019-08-01: Changed the examples from “shelves” to “publishers”, to present a better example of resource ownership.
- 2019-06-10: Added guidance for long-running delete.
- 2019-05-29: Added an explicit prohibition on arbitrary fields in standard methods.