AIP-235 批量方法:Delete
编号 | 235 |
---|---|
原文链接 | AIP-235: Batch methods: Delete |
状态 | 批准 |
创建日期 | 2019-06-18 |
更新日期 | 2025-03-06 |
一些API允许用户在单个事务中删除一系列资源。批量删除方法提供了这个功能。
指南
API 可以 使用下列两种模式支持批量删除:
以同步方式返回应答。
rpc BatchDeleteBooks(BatchDeleteBooksRequest) returns (google.protobuf.Empty) {option (google.api.http) = {post: "/v1/{parent=publishers/*}/books:batchDelete"body: "*"};
}
返回操作对象,以异步方式确定应答。
rpc BatchDeleteBooks(BatchDeleteBooksRequest) returns (google.longrunning.Operation) {option (google.api.http) = {post: "/v1/{parent=publishers/*}/books:batchDelete"body: "*"};option (google.longrunning.operation_info) = {response_type: "google.protobuf.Empty"metadata_type: "BatchDeleteBooksOperationMetadata"};
}
- 远程过程调用的名字 必须 以
BatchDelete
开头。远程过程调用名字的其余部分 应当 是所删除资源的复数形式。 - 请求消息 必须 与远程过程调用名字一致,带有
Request
后缀。 - 应答消息 应当 是
google.protobuf.Empty
。- 如果使用软删除,应答消息 应当 包含已经更新的资源。
- 如果批量方法返回
google.longrunning.Operation
对象, 必须 同时返回response_type
和metadata_type
域。- 如果使用软删除,
response_type
应当 是包含已更新资源的消息。
- 如果使用软删除,
- HTTP动词 必须 是
POST
。 - HTTP URI 必须 以
:batchDelete
结尾。 - URI路径 应当 表示资源集合,与简单CRUD操作中使用的集合一致。如果操作跨越多个上级, 可以 使用破折号(
-
)作为通配符。 google.api.http
注解中的body子句 应当 是"*"
。
原子性和部分成功
- 批量删除方法 可以 是原子的(要求全部删除成功,要么全都不删除)或支持部分成功。选择时请考虑下列因素:
- 保证原子性所需的复杂度:使用简单数据库事务的操作 应当 作为原子操作。涉及管理复杂资源的操作 应当 作为部分成功操作。
- 终端用户体验:考虑API消费者视角。原子行为适合这个场景吗,这意味着少数条目有问题将导致大批量失败。
- 同步批量删除 必须 是原子的。
- 异步批量删除 可以 支持原子性或部分成功。
- 如果支持部分成功,参考操作元数据消息要求。
请求消息
批量删除方法请求 应当 使用以下模式指定:
message BatchDeleteBooksRequest {// The parent resource shared by all books being deleted.// Format: publishers/{publisher}// If this is set, the parent of all of the books specified in `names`// must match this field.string parent = 1 [(google.api.resource_reference) = {child_type: "library.googleapis.com/Book"}];// The names of the books to delete.// A maximum of 1000 books can be deleted in a batch.// format: publishers/{publisher}/books/{book}repeated string names = 2 [(google.api.field_behavior) = REQUIRED,(google.api.resource_reference) = {type: "library.googleapis.com/Book"}];
}
- 应当 包含
parent
域,待删除的是顶级资源时除外。如果调用者设定了这个域,但与请求中某个子消息的parent
域不一致,调用 必须 失败。- 如果每个请求只允许设置一个上级,此域 应当 是必需域。
- 域 应当 标识所引用的资源类型。
- 域的注释 应当 记录资源模式。
- 请求消息 必须 包含一个重复域,接受设定待删除资源的消息,如同标准删除方法。域 应当 名为
requests
。- 域 应当 是必需域。
- 域 应当 标识所引用的资源类型。
- 域的注释 应当 记录资源模式。
- 除
name
之外的域 可以 从标准删除请求中“提升”。没有办法让这些域针对不同资源接受不同的值。如果需要这么做,请使用备选请求消息格式。 - 请求消息 不得 包含任何其他必填域, 不应 任何其他可选域。本AIP或其他AIP另有要求的除外。
names
域上方的注释 应当 记录所允许的最大请求数。- 不得 支持基于过滤器的匹配。
包含标准删除消息的请求消息
如果除了资源名字之外,请求删除的各个资源还存在值不相同的域,那么批量消息 可以 包含标准删除请求消息重复域。通常不建议这么做,除非确实需要。
批量删除请求方法 应当 使用下列模式指定:
message BatchDeleteBooksRequest {// The parent resource shared by all books being deleted.// Format: publishers/{publisher}// If this is set, the parent of all of the books specified in the// DeleteBookRequest messages must match this field.string parent = 1 [(google.api.resource_reference) = {child_type: "library.googleapis.com/Book"}];// The requests specifying the books to delete.// A maximum of 1000 books can be deleted in a batch.repeated DeleteBookRequest requests = 2[(google.api.field_behavior) = REQUIRED];
}
- 应当 包含
parent
域。如果调用者设定了这个域,但与请求中某个子消息的parent
域不一致,调用 必须 失败。- 如果每个请求只允许设置一个上级,此域 应当 是必需域。
- 域 应当 标识所引用的资源类型。
- 域的注释 应当 记录资源模式。
- 请求消息 必须 包含一个重复域,接受设定待删除资源的消息,如同标准删除方法。域 应当 名为
requests
。- 域 应当 是必需域。
- 其他的域 可以 从标准删除请求中“提升”。意味着这些域可以在批量级别或子消息级别设定。与
parent
类似,如果批量级别和子消息级别都对同一个域设定了值,值 必须 一致。- 必须保持唯一的域不能提升(例如etag)。
- 请求消息 不得 包含任何其他必填域, 不应 任何其他可选域。本AIP或其他AIP另有要求的除外。
requests
域上方的注释 应当 记录所允许的最大请求数。- 不得 支持基于过滤器的匹配,除非缺少这个特定将无法支持关键场景。这使得用户非常容易意外删除重要数据。如果必须如此,请参考AIP-165。
应答消息(只限于软删除)
对于使用软删除,需要返回应答消息的场景,应答 应当 使用以下模式指定:
message BatchDeleteBooksResponse {// Books created.repeated Book books = 1;
}
- 应答消息 必须 包含一个重复域,对应软删除的资源。
操作元数据消息
metadata_type
消息 必须 要么与远程过程调用名字一致,并带有OperationMetadata
后缀;要么在类型被多个批量方法共享时,以Batch
前缀和OperationMetadata
后缀命名。- 如果批量删除方法支持部分成功,元数据消息 必须 包含
map<int32, google.rpc.Status> failed_requests
域,传递部分失败信息。- map中的键是批量请求
requests
域中子消息的下标。 - map条目中的值 必须 是可能被通常标准删除方法调用返回的错误。
- 如果失败的请求通过服务端重试最终成功,期间暂时的错误 不得 通过
failed_requests
传递。 - 如果批量中的请求全部失败, 必须 将
Operation.error
设定为code = google.rpc.Code.Aborted
和message = "None of the requests succeeded, refer to the BatchDeleteBooksOperationMetadata.failed_requests for individual error details"
。
- map中的键是批量请求
- 元数据消息 可以 包含其他域,传递操作进度信息。
适配部分成功
为了让现存批量API适配部分成功模式,API必须执行:
- 必须保持默认行为,避免不兼容的行为变化。
- 如果API返回
Operation
:- 请求消息 必须 包含
bool return_partial_success
域。 Operation
metadata_type
必须 包含map<int32, google.rpc.Status> failed_requests
域。- 如果请求的
bool return_partial_success
设定为真,API应当支持部分成功行为;否则应当继续保持默认的原子行为。
- 请求消息 必须 包含
- 如果API直接同步返回应答:
- 由于现存客户端将成功应答视为原子操作,现存API版本 不得 适配部分成功模式。
- 必须 删除新版本,返回
Operation
,并遵守本文档描述的部分成功模式。
理由
要求同步批量方法是原子的
同步批量方法必须是原子的,这一要求来自于下列思考:
在本AIP的早期版本建议批量方法是原子的。没有直观的方法能在同步应答状态码中表达部分失败,因为成功暗示一切正常。因此在应答中添加新域表示部分失败,将造成破坏性变更,因为现存客户端会将成功应答解释为全部资源都已删除。
另一方面,如同AIP-193所描述, Operation
更适合表达部分状态。 Operation
的应答状态码不会传递具体的操作结果,客户端需要检查应答消息体,判断操作是否成功。
传递部分失败
本AIP推荐使用 map<int32, google.rpc.Status> failed_requests
域传递部分失败,其中键是失败请求在原始批量请求中的下标。其他考虑过的选项有:
repeated google.rpc.Status
域。这个选项由于无法清晰确定条目所对应的原始请求而被否决。map<string, google.rpc.Status
域。其中键是失败请求的标识。该选项被否决的原因是:- 为了读取部分成功应答,客户端需要维护请求标识到请求对象的映射。
- 如果服务无法保证多个批量请求中,同一请求的幂等性,通过请求标识来传递错误的行为可能违背AIP-155。
repeated FailedRequest
域。其中FailedRequest
包含单独的删除请求和google.rpc.Status
。由于在用户数据保护方面存在难题,不建议在应答消息中返回请求内容,因此否决此选项。
修订记录
- 2025-03-06 添加部分成功行为详细指南,以及选择原子或部分成功方案的决策框架。
- 2022-06-02 修改后缀描述,消除多余的“-”。
- 2020-09-16 建议注释
parent
、names
和requests
域。 - 2020-08-27 删除关于顶级资源上级的建议。
- 2020-03-27 添加对AIP-165按条件删除的引用,
- 2019-10-11 将优先推荐方案改为使用重复字符串域,而非重复标准删除请求消息。原推荐方案移至独立章节。
- 2019-09-11 修复关于上级域和下级域必须一致的文字。
- 2019-08-01 将示例从“书架”更改为“出版商”,提供更好的资源所有权示例。