AIP-4210
```org #+BEGIN_SRC emacs-lisp
客户端库生成器
API指南的存在是为了促进简单、直观和一致的API。熟悉通常遵循AIP指导的API的用户能够将他们在先前API中学到的知识应用到新的API中。
客户端库为用户提供了一种更快地开始使用API的机制,通过简化常见问题(如认证)以及通过语言原生的方式调用API端点并接收语言原生的响应。然而,为了使这些库提供最大的价值,它们也必须是简单、直观和一致的。代码生成器提供了一种大规模生成一致客户端库的手段。
遵循这些AIP标准的代码生成器被称为“生成的API客户端生成器”,简称_GAPIC生成器_。生成的库通常被称为_GAPIC_。
注意: 由于本AIP以语言中立的方式描述指导和需求,它使用了可能在某些语言或环境中不精确或不合适的通用术语(例如,使用术语`class`,尽管像Go这样的语言没有类)。本AIP对词汇的特殊使用最好理解为对原则的解释,并不期望严格遵守本AIP中的确切词汇。
指导
大多数支持语言的客户端库和支持代码的代码生成的一般流程如下所述。
注意: 此模式的例外通常是由于使用了独特的堆栈,例如Node.js使用`protobuf.js`和`grpc-node`,它们没有代码生成,或者Python使用`proto-plus-python`中的protobuf包装器,但一般的GAPIC流程保持不变。
```graphviz digraph { node [ style=“filled,solid” shape=box fontname=“Roboto” ]; splines=ortho; nodesep=0.3; center=true;
proto [ label=“API Protobuf\nDescriptors” shape=rectangle fillcolor=aliceblue ];
subgraph cluster_code_generators { rank = same; style = filled; fillcolor = lightgrey; node [ shape=oval ];
protobuf [ label=“protobuf\ngenerator” fillcolor=deepskyblue3 ]; grpc [ label=“gRPC\ngenerator” fillcolor=gold3 ]; gapic [ label=“GAPIC\ngenerator” fillcolor=darkseagreen ]; }
proto -> protobuf; proto -> grpc; proto -> gapic;
subgraph cluster_generated_code { rank = same; style = filled; fillcolor = lightgrey; node [ shape=rectangle ];
protobuf_output [ label=“Message & Enum\nCode” fillcolor=deepskyblue3 ]; grpc_output [ label=“Server & Client\nStubs” fillcolor=gold3 ]; gapic_output [ label=“Google API\nClient” fillcolor=darkseagreen ]; }
protobuf -> protobuf_output; grpc -> grpc_output; gapic -> gapic_output;
assembly [ label=“Package\nassembly” shape=oval fillcolor=aliceblue ];
protobuf_output -> assembly grpc_output -> assembly gapic_output -> assembly
assembled_package [ label=“Package of\ngenerated code” fillcolor=aliceblue ];
assembly -> assembled_package } ```
以下部分重点介绍上图中的“GAPIC生成器”。
Protobuf插件
protobuf编译器`protoc`支持代码生成的插件系统。插件系统允许用任何语言编写插件,并为任何语言编写插件。
代码生成器**必须**作为`protoc`插件实现。以下规则适用于作为`protoc`插件实现的客户端库生成器:
- 插件**应该**用目标生成语言编写。
- `protoc`期望插件是`$PATH`中的可执行文件,并命名为`protoc-gen-{plugin_name}`,对应于发送给`protoc`可执行文件的`–{plugin_name}_out`选项。因此:
- 插件可执行文件**应该**命名为`protoc-gen-{lang}_gapic`
- 插件选项**应该**遵循`–{lang}_gapic_out`的约定
- 插件**不得**利用`protoc`“插入点”。尽管`protoc`插件文档表明存在插入点,但Protobuf团队不支持也不鼓励使用它们。
CLI选项
代码生成器**应该**能够在没有任何选项或标志的情况下运行,并且能够仅从protos生成有效的库。如果需要选项,`protoc`允许将它们作为`–{plugin_name}_opt`传递,并且此处提供的字符串将设置为`CodeGeneratorRequest`上的`parameter`字符串。
重要: `CodeGeneratorRequest.parameter`值是执行时出现的所有相关插件选项值的逗号分隔字符串。这意味着逗号不能用于分隔类似列表的插件选项值。
代码生成器**不得**依赖环境变量进行配置。
预期行为
本节概述了客户端库生成器输出的预期行为属性(换句话说:生成器编写的库)。客户端库**必须**实现这些概念才能被视为完整。
消息和枚举
客户端库生成器**不应**为已经由Protobuf提供的代码生成器生成的`message`或`enum`描述符生成代码。
服务和方法
请求的protos中的每个`service`和`rpc`指令**必须**在客户端库输出中表示,除非语言或传输无法支持它。
注意: 尽管如何实现这一点可能因语言而异,但在大多数经典语言中,它可能是每个服务的类,包含每个RPC的方法。
- 为每个`service`指令生成的类**必须**遵守`google.api.default_host`注释(如果提供),并使用该主机作为默认主机名。这些类**应该**提供一种机制,供最终用户覆盖主机名。
- 如果`service`指令上没有`google.api.default_host`注释,则生成的类**应该**在实例化时要求主机名。
- 此外,如果为每个服务生成的类支持使用OAuth和服务凭据,它们**必须**遵守`google.api.oauth_scopes`注释(如果提供),并默认使用这些范围。
- 已将`deprecated` protobuf选项设置为`true`的服务**应该**在生成的类中生成等效的弃用标签。如果适用,此标签可能包括指定服务何时将被删除的注释,通常是下一个主要版本更新。同样,将此选项设置为`true`的RPC**应该**将其生成的语言方法标记为弃用。
- 最后,服务类**必须**也接受凭据,这些凭据在发出请求时适当使用。(接受自定义gRPC通道满足此要求。)
- 代码生成器**不得**生成客户端_存根_类,这些类通常由gRPC生成,除了客户端库类之外。
长时间运行的操作
RPC被认为是“长时间运行”的RPC,当且仅当RPC的返回类型是`google.longrunning.Operation`。任何具有一个或多个返回`Operation`的RPC的API都期望实现`Operations`服务。
由于`Operation`中的`response`和`metadata`字段是`google.protobuf.Any`类型,因此有必要知道使用什么消息来反序列化它们。这是使用`google.longrunning.operation_info`注释在RPC上注释的。
注意: 此结构中的值是_字符串_,而不是消息对象;代码生成器使用字符串来确定要使用的适当消息。没有句点(`.`)字符的字符串引用同一proto包中的消息。
如果`operation_info`注释中提供的类型未导入,或者未提供响应类型或元数据类型,代码生成器**应该**失败并报错。如果省略`response_type`或`metadata_type`键中的_任何一个_,代码生成器**应该**失败并报错。
客户端库**必须**遵守LRO接口;如果RPC的返回类型是`Operation`,则生成的方法**必须**拦截它并返回适当的惯用对象以解析LRO(例如绑定到基础`Operation`对象的`Future`或`Promise`)。
流式传输
客户端库**必须**在其支持的传输允许的范围内实现流式传输。如果在参数或响应类型上存在`stream`关键字,则RPC被认为是流式传输的。这在`MethodDescriptorProto`消息中使用`client_streaming`和`server_streaming`键表示。
变更日志
- **2023-06-22**:添加了代码生成图、消息/枚举指导,并清理了插件和选项指导。
#+END_SRC ```