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_PRECONDITION
toABORTED
making 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.