tommwq.work/aip

AIP-191 文件和目录结构

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

统一的文件和目录结构,虽然在技术上差别不大,但可以让用户和审查者更容易阅读API界面定义。

指南

注意 以下指南适合于使用protobuf定义的API,例如Google内部使用的API。本指南的主要思想同样适合于使用其他规范性语言或格式定义的API,但有些具体建议可能无效。

语法

使用protocol buffer定义API时 必须 使用 proto3 语法。

同一个包

使用protocol buffer定义的API, 必须 在同一个包中定义独立的API,包名 必须 以版本号结尾。例如:

syntax = "proto3";

package google.cloud.translation.v3;

Google API 必须 位于和protocol buffer package 指令一致的目录中。例如,上述包对应的目录为 google/cloud/translation/v3

文件名

将API定义分拆成多个文件通常很有用。文件名 必须 使用 snake_case

API 应当 有一个显著的“入口”文件,通常以API本身命名。具有少量接口的API(例如Google Cloud Pub/Sub的 PublisherSubscriber可以 为每个服务设置独立的入口文件。

只有一个文件的API 应当 使用与API名字一致的文件名。

API service 和远程过程调用请求及应答 message 应当 在同一文件中定义。

请记住,文件名通常会成为客户端库中的模块名,客户会在 importuse 语句中使用它们。因此,选择一个描述性强,并且不包含语言关键字的文件名非常重要。例如名为 import.proto 的文件在Python中可能会遇到问题。

注意 版本 不得 用作文件名,这会在客户端库中产生奇怪的导入语句。禁止使用诸如 v3.protov1beta1.proto 的文件名。

文件布局

在文件中,高级别和重要定义 应当 放在低级别和次要定义之前。

在proto文件中,组件 应当 按以下顺序排列。每个部分之间 应当 用空行分隔:

  • 版权和许可证声明(如果需要)。
  • proto syntax 语句。
  • proto package 语句。
  • 任何 import 语句,按字母序排列。
  • 文件级别的 option 语句。
  • 服务 service 定义。
    • 方法 应当 按照所使用的资源分组,标准方法 应当 放在自定义方法之前。
  • 资源 message 定义。上级资源 必须 在下级资源之前定义。
  • 远程过程调用请求和应答 message 定义,按相应方法的顺序排列。每个请求消息 必须 在其对应的应答消息(如果有)之前。
  • 其他 message 定义。
  • 顶级 enum 定义。

包选项

protocol buffer可以包含选项,声明生成代码的包或名字空间(取决于目标编程语言)。例如,声明 go_packagecsharp_namespace 将会覆盖自动推断的包名。

定义API时,遵守以下规则:

  • Java
    • 必须 设置 java_package 。正确的值通常是带有顶级域名前缀的proto包名。例如 com.google.example.v1
    • 必须java_multiple_files 设置为 true
    • 必须 设置 java_outer_classname应当 将其设置为proto文件名,使用 PascalCase 并添加后缀 Proto 。例如 LibraryProto
  • 其他语言
    • 对于其他语言的包或名字空间指令, 必须 要么在proto包的每个文件中都设置,要么全都不设置。如果设置了,每个文件中的值 必须 相同。
    • 如果proto包的某部分是复合名字(例如accessapproval), 必须 指定C#、Ruby和PHP选项,以处理 PascalCase 分词位置。例如:
      option csharp_namespace = "Google.Cloud.AccessApproval.V1";
      option php_namespace = "Google\\Cloud\\AccessApproval\\V1";
      option ruby_package = "Google::Cloud::AccessApproval::V1";
      
    • go_package 值直接取决于Go代码的管理方式,即模块名字是基于VCS还是使用远程导入路径。但二者通常具有相同结构。
      • 模块 可能 因产品领域而异,例如 google.cloud.accessapproval.v1 出现在模块 cloud.google.com/go/accessapproval 中。
      • 包导入路径 应当 从proto包派生。
      • proto包名中的API版本 应当api 为前缀,例如proto包名中的 v1 变为 apiv1
      • 导入路径末端 应当 基于proto包名中的产品名字,并且 必须pb 为后缀,例如 accessapproval 变为 accessapprovalpb
      • 具体值 应当 由管理生成代码的团队决定。

所有包选项 应当 按名字的字母序排列。关于语言包选项的更多信息,请参考Protocol Buffer文档

重要 虽然Java之外的其他语言对于没有复合名字的API有合理的默认值,但请注意, 添加 选项(值不等于默认值)将对该语言客户端产生破坏性更改。在发布proto时,请确认省略选项是有意为之的。

理由

Java包选项

将选项 java_multiple_files 设置为 true 可以获得更清晰的文件结构。它让 protoc 为每个Protocol Buffer类型创建独立的输出文件,从而允许更细粒度的导入。选项 java_outer_classname 必须配合 java_multiple_files 选项使用。它让 protoc 将每个Protocol Buffer类型包装在Java类中,类名字是选项值。这可以防止生成的类之间存在名字冲突。

Go包选项

Go包选项由管理生成代码的团队决定,因为它与团队的源代码管理实践有直接关系。允许每个proto包自行决定其Go包,将导致代码管理出现不一致和摩擦。在Go客户端团队内部,保持统一的Go包名字结构对于统一的用户体验至关重要。

修订记录

  • 2024-06-13 添加Go包选项指南。
  • 2024-06-05 添加Java包选项理由。
  • 2023-02-24 添加关于protocol buffer语法的指南。
  • 2022-10-18 添加关于Ruby/PHP/C#选项的指南。
  • 2019-11-18 添加关于包选项的指南。