AIP-144 重复域
·
[tommwq@126.com]
编号 | 144 |
---|---|
原文链接 | https://google.aip.dev/144 |
状态 | 批准 |
创建日期 | 2020-03-19 |
更新日期 | 2020-03-19 |
在API中表示数据列表比看起来要复杂。用户常常需要原地修改列表,如果单个资源中存在较长数据序列,将对分页带来困难。
指南
资源 可以 在适当的地方使用重复域。
message Book {
option (google.api.resource) = {
type: "library.googleapis.com/Book"
pattern: "publishers/{publisher}/books/{book}"
};
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
repeated string authors = 2;
}
- 重复域 必须 使用复数形式的域名字。
- 如果单数和复数形式相同(如“moose”、“info”), 必须 使用实际存在的词汇,而非试图创造新的复数形式。
- 重复域 应当 存在强制上限,防止单个资源负载过大。一个好的经验法则是100个元素。
- 如果重复数据可能超过上限,API 应当 使用子资源代替。
- 重复域 不得 内联表示其他资源的主体。相反,消息 应当 提供关联资源的名字。
标量和消息
如果确认未来不需要额外数据,重复域 应当 使用标量类型(如 string
),使用消息类型会显著增加认知负担,产生复杂代码。
然而,如果未来可能需要额外数据,重复域 应当 主动使用消息而非标量,以避免平行的重复域。
更新策略
资源 可以 使用两种策略执行重复域更新操作:使用标准Update方法直接更新,或使用自定义的 Add
和 Remove
方法。
标准 Update
方法存在一个重要限制:用户只能更新 完整 列表。域掩码无法处理重复域中的单个条目。这意味着用户必须读取资源,根据需要修改重复域值,再发送回去。这适用于很多场景,特别是重复域数据比较少(少于10个左右),且不存在竟态条件问题,或者可以使用ETags进行保护的时候。
注意 声明友好资源 必须 使用标准
Update
方法,不要引入Add
和Remove
方法。如果声明式工具需要在忽略其他关系的情况下推理特定关系,考虑使用子资源。
如果需要原子修改操作,API 应当 使用动词 Add
和 Remove
提供自定义方法:
注意 如果这两种策略限制性过强,考虑使用子资源。
rpc AddAuthor(AddAuthorRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{book=publishers/*/books/*}:addAuthor"
body: "*"
};
}
rpc RemoveAuthor(RemoveAuthorRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{book=publishers/*/books/*}:removeAuthor"
body: "*"
};
}
- 添加或删除的数据 应当 使用基础类型(通常是
string
)。- 对于具有主键的复杂数据结构,API 应当 使用包含 map 类型域的
Update
方法。
- 对于具有主键的复杂数据结构,API 应当 使用包含 map 类型域的
- 接口名字 必须 以
Add
或Remove
开头。其余部分 应当 是待添加域的单数形式。 - 请求消息 必须 与接口名字一致,并带有
Request
后缀。 - 应答消息 应当 是资源自身,应答包含有效上下文信息的除外。此时应答消息必须与接口名字一致,并带有
Response
后缀。- 当应答是资源自身时, 应当 包含资源的完整数据。
- HTTP动词 必须 使用
POST
,这是自定义方法惯例。 - HTTP URI 必须 以
:add*
或:remove*
结尾,其中*
是待添加或删除域的下划线风格单数名字。 - 请求消息中,传递资源名字的域 应当 映射到URI路径。
- HTTP变量 应当 是资源名字(如
book
)而非name
或parent
。 - 变量 应当 是URI路径中唯一的变量。
- HTTP变量 应当 是资源名字(如
google.api.http
注解的body
子句 应当 是"*"
。- 如果
Add
接口中添加的数据已经存在,方法 必须 返回ALREADY_EXISTS
错误。 - 如果
Remove
接口中删除的数据不存在,方法 必须 返回NOT_FOUND
错误。
请求消息
message AddAuthorRequest {
// The name of the book to add an author to.
string book = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference).type = "library.googleapis.com/Book"
];
string author = 2 [(google.api.field_behavior) = REQUIRED];
}
message RemoveAuthorRequest {
// The name of the book to remove an author from.
string book = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference).type = "library.googleapis.com/Book"
];
string author = 2 [(google.api.field_behavior) = REQUIRED];
}
- 必须 包含资源域。域 应当 是资源名字(如
book
)而非name
或parent
。 - 必须 包含待添加或删除值的域。 应当 是域的单数名字。
- 域 应当 被注解为必需域。
- 请求消息 不得 包含任何其他必需域, 不应 包含其他可选域,本AIP或另外AIP要求的除外。
变更日志
- 2022-06-02 更改后缀描述,消除多余的“-”。
- 2020-10-17 建议在Add和Remove接口中返回资源自身,而非单独的应答类型。
- 2020-10-17 添加了Add和Remove接口及请求指南。