tommwq.work/aip

AIP-136 自定义方法

· [tommwq@126.com]
编号 136
原文链接 https://google.aip.dev/136
状态 批准
创建日期 2025-01-09
更新日期 2019-01-25

面向资源设计(AIP-121)提供了自定义方法,作为表达难以用标准方法建模的行为的手段。自定义方法很重要,它们提供了让API词汇表符合用户意图的手段。

指南

自定义方法 应当 只用于难以使用标准方法表达的功能;如果可能,优先使用标准方法,它们具有统一的语义。(当然,这仅限于所讨论的功能实际上符合正常语义的情况;试图强行让标准方法“勉强工作”,不是好想法。)

虽然自定义方法的设计方法很宽泛,但许多原则是一致的:

// Archives the given book.
rpc ArchiveBook(ArchiveBookRequest) returns (ArchiveBookResponse) {
  option (google.api.http) = {
    post: "/v1/{name=publishers/*/books/*}:archive"
    body: "*"
  };
}

注意 上面的模式展示了操作特定资源的自定义方法。自定义方法可以同资源、集合或服务关联。以下几点适用于所有三种情况。

  • 方法名字 应当 是动词后接名词。
    • 名字 不得 包含介词(“for”、“with”等)。
    • 名字中的动词 不应 包含任何标准方法动词(GetListCreateUpdateDelete)。
    • 名字 不得 包含词汇 Async 。相反,如果意图要区分即时接口和耗时接口,可以使用后缀 LongRunning 。例如,要开发一个创建书籍的耗时接口(如果标准方法 CreateBook 在设计时没有考虑耗时因素),可以引入自定义的 CreateBookLongRunning 方法。
  • HTTP方法 必须GETPOST
    • GET 必须 用于获取数据或资源状态的方法。
    • POST 必须 用于存在副作用或修改资源和数据的方法。
  • HTTP URI 必须 使用 : 字符后接自定义动词(如上例中的 :archive ),URI中的动词 必须 与接口名字中的动词一致。
    • 如果需要分隔单词, 必须 使用 camelCase
  • google.api.http 注解中的 body 子句 应当"*"
  • 自定义方法 应当 采用与接口名字一致的请求消息,并带有 Request 后缀。
  • 自定义方法 应当 返回与接口名字一致的应答消息,并带有 Response 后缀。
    • 在操作特定资源时,自定义方法 可以 返回资源本身。

基于资源的自定义方法

如果API可以使用资源建模,自定义方法 必须 对资源执行操作:

// Archives the given book.
rpc ArchiveBook(ArchiveBookRequest) returns (ArchiveBookResponse) {
  option (google.api.http) = {
    post: "/v1/{name=publishers/*/books/*}:archive"
    body: "*"
  };
}
  • 资源名字参数 必须 称为 name ,是URI路径中唯一的变量。

基于集合的自定义方法

虽然大多数自定义方法操作单个资源,但某些自定义方法 可以 操作集合:

// Sorts the books from this publisher.
rpc SortBooks(SortBooksRequest) returns (SortBooksResponse) {
  option (google.api.http) = {
    post: "/v1/{parent=publishers/*}/books:sort"
    body: "*"
  };
}
  • 集合的上级资源 必须 称为 parent ,是URI路径中唯一的变量。
  • 集合键(如上例中的 books必须 为字面值。

无状态方法

一些自定义方法和资源没有关联。这些方法通常是 无状态 的:它们接受请求返回应答,对API内的数据没有持久性影响。

// Translates the provided text from one language to another.
rpc TranslateText(TranslateTextRequest) returns (TranslateTextResponse) {
  option (google.api.http) = {
    post: "/v1/{project=projects/*}:translateText"
    body: "*"
  };
}
  • 如果方法在特定范围内运行(如上例中的 project ),请求消息中的域名字 应当 是范围资源的名字。如果需要分隔单词, 必须 使用 snake_case
  • URI 应当 将动词和名词放在 : 分隔符后(此时因为没有集合,不要在URI中使用“假集合键”)。例如 :translateTexttext:translate 更好。
  • 如果和费用有关,无状态方法 必须 使用 POST

声明友好资源

声明友好资源通常 不应 使用自定义方法(在其他AIP中讨论的特定声明友好自定义方法除外),因为声明友好工具无法自动确定如何处理它们。

一个例外是那些很少使用的、本质上属于命令式的操作,例如 MoveRename 操作,这些操作通常不会期望有声明式支持。

理由

HTTP路径

和标准方法类似,操作资源或集合的自定义方法需要 nameparent 参数指明操作目标资源。这个约定允许客户端将自定义方法映射到适当的资源。

HTTP方法

同时使用HTTP动词 GETPOST 可以明确区分哪些方法会修改数据,哪些不会。只读方法在一些客户端中具有优先概念(如Terraform中的DataSources),并明确指示用户哪些方法在调用时没有运行风险。

禁止使用介词

通常来说,如果方法名中出现介词,往往意味着不该使用新方法,而是应该将域添加到现有方法中,或者应该使用另一个更明确的动词。例如,如果已经存在 CreateBook 消息,而你考虑添加 CreateBookFromDictation 方法,可以考虑替换成 TranscribeBook 方法。同样的,如果存在需要按照特定属性查找的方法,与其使用 GetBookByAuthor ,不如考虑使用 SearchBooks ,并将 author 域用作搜索条件。

接口名字

词汇“async”通常用在编程语言中,表明特定方法(包括远程方法)调用是同步或异步的。同步/异步概念与接口本身是否是耗时操作处于不同的抽象层次。在接口名字中使用“async”会引发混淆,甚至可能导致一些语言的客户端库在生成调用接口的同步和异步方法时出现问题。

修订记录

  • 2025-01-09 添加禁止在方法名中使用介词的理由。
  • 2023-11-16 包含指向AIP-127“HTTP和gRPC转码”的链接,以便读者获取有关 body 定义的指导。
  • 2023-05-16 添加禁止在接口名中使用词汇“async”的规定。
  • 2023-05-09 添加关于 POSTGET 的指南,要求使用 parent 而非资源的单数形式。
  • 2023-03-02 明确不建议使用标准方法动词。
  • 2022-06-02 修改后缀描述,去除多余的“-”。
  • 2020-10-06 添加声明友好指南。
  • 2019-08-01 将示例从“shelves”改为“publishers”,提供更好的资源所有权示例。