本章将讨论如何在 API 设计中使用自定义方法。 自定义方法是指 5 个标准方法之外的 API 方法。这些方法应该仅用于标准方法不易表达的功能。通常情况下,API 设计者应该尽可能优先考虑使用标准方法,而不是自定义方法。标准方法具有大多数开发者熟悉的更简单且定义明确的语义,因此更易于使用且不易出错。另一项优势是 API 平台更加了解和支持标准方法,例如计费、错误处理、日志记录、监控。 自定义方法可以与资源、集合或服务关联。 它可以接受任意请求和返回任意响应,并且还支持流式请求和响应。 自定义方法名称必须遵循方法命名惯例。
HTTP 映射
对于自定义方法,它们应该使用以下通用 HTTP 映射:
https://service.name/v1/some/resource/name:customVerb
使用 :
而不是 /
将自定义动词与资源名称分开以便支持任意路径。例如,恢复删除文件可以映射到 POST /files/a/long/file/name:undelete
选择 HTTP 映射时,应遵循以下准则:
- 自定义方法应该使用 HTTP
POST
动词,因为该动词具有最灵活的语义,但作为替代 get 或 list 的方法(如有可能,可以使用GET
)除外。(详情请参阅第三条。) - 自定义方法不应该使用 HTTP
PATCH
,但可以使用其他 HTTP 动词。在这种情况下,方法必须遵循该动词的标准 HTTP 语义。 - 请注意,使用 HTTP
GET
的自定义方法必须具有幂等性并且无负面影响。例如,在资源上实现特殊视图的自定义方法应该使用 HTTPGET
。 - 接收与自定义方法关联的资源或集合的资源名称的请求消息字段应该映射到网址路径。
- 网址路径必须以包含冒号(后跟自定义动词)的后缀结尾。
- 如果用于自定义方法的 HTTP 动词允许 HTTP 请求正文(其适用于
POST
、PUT
、PATCH
或自定义 HTTP 动词),则此自定义方法的 HTTP 配置必须使用body: "*"
子句,所有其他请求消息字段都应映射到 HTTP 请求正文。 - 如果用于自定义方法的 HTTP 动词不接受 HTTP 请求正文(
GET
、DELETE
),则此方法的 HTTP 配置不得使用body
子句,并且所有其他请求消息字段都应映射到网址查询参数。
警告:如果一个服务会实现多个 API,API 生产者必须仔细创建服务配置,以避免 API 之间的自定义动词发生冲突。
// This is a service level custom method.
rpc Watch(WatchRequest) returns (WatchResponse) {
// Custom method maps to HTTP POST. All request parameters go into body.
option (google.api.http) = {
post: "/v1:watch"
body: "*"
};
}
// This is a collection level custom method.
rpc ClearEvents(ClearEventsRequest) returns (ClearEventsResponse) {
option (google.api.http) = {
post: "/v3/events:clear"
body: "*"
};
}
// This is a resource level custom method.
rpc CancelEvent(CancelEventRequest) returns (CancelEventResponse) {
option (google.api.http) = {
post: "/v3/{name=events/*}:cancel"
body: "*"
};
}
// This is a batch get custom method.
rpc BatchGetEvents(BatchGetEventsRequest) returns (BatchGetEventsResponse) {
// The batch get method maps to HTTP GET verb.
option (google.api.http) = {
get: "/v3/events:batchGet"
};
}
用例
自定义方法适用于以下场景:
- 重启虚拟机。 设计备选方案可能是“在重启集合中创建一个重启资源”,这会让人感觉过于复杂,或者“虚拟机具有可变状态,客户端可以将状态从 RUNNING 更新到 RESTARTING”,这会产生可能存在哪些其他状态转换的问题。 此外,重启是一个常见概念,可以合理转化为一个自定义方法,从直观上来说符合开发者的预期。
- 发送邮件。 创建一个电子邮件消息不一定意味着要发送它(草稿)。与设计备选方案(将消息移动到“发件箱”集合)相比,自定义方法更容易被 API 用户发现,并且可以更直接地对概念进行建模。
- 提拔员工。 如果作为标准
update
方法实现,客户端需要复制企业提拔流程管理政策,以确保提拔发生在正确的级别,并属于同一职业阶梯等等。 - 批处理方法。 对于对性能要求苛刻的方法,提供自定义批处理方法可以有助于减少每个请求的开销。例如,accounts.locations.batchGet。
以下是标准方法比自定义方法更适用的示例:
- 使用不同查询参数的查询资源(使用带有标准列表过滤的标准
list
方法)。 - 简单的资源属性更改(使用带有字段掩码的标准
update
方法)。 - 关闭一个通知(使用标准
delete
方法)。
常用自定义方法
以下是常用或有用的自定义方法名称的精选列表。API 设计者在引入自己的名称之前应该考虑使用这些名称,以提高 API 之间的一致性。
方法名称 | 自定义动词 | HTTP 动词 | 备注 |
---|---|---|---|
Cancel | :cancel | POST | 取消一个未完成的操作,例如 operations.cancel 。 |
BatchGet | :batchGet | GET | 批量获取多个资源。如需了解详情,请参阅列表描述。 |
Move | :move | POST | 将资源从一个父级移动到另一个父级,例如 folders.move 。 |
Search | :search | GET | List 的替代方法,用于获取不符合 List 语义的数据,例如 services.search 。 |
Undelete | :undelete | POST | 恢复之前删除的资源,例如 services.undelete 。建议的保留期限为 30 天。 |