翻译自 API Design Guide - Naming Conventions

为了在长期和大量使用的 API 中提供统一的开发体验,API 中的所有名字 应该(should) :

  • 简单

  • 直观

  • 一致

此文章讨论了接口、资源、集合、方法和消息的名字。

因为很多开发者的母语并不是英语,这些命名约定通过鼓励使用简单、统一的短词汇来命名方法和资源来保证大部分开发者能够容易理解 API。

  • API 中的名字 应该(should) 使用美式英语,例如:license(不是 licence),color(不是 colour)。

  • 使用常用的简短形式或缩写,例如: API 比 Application Programming Interface 更好。

  • 尽量使用直接、熟悉的术语,例如:描述对资源的删除(销毁)时,delete 比 erase 更好。

  • 对相同的概念使用相同的名字或术语,包括在 API 中共享的概念。

  • 避免名字重用,对不同的概念要使用不同名字。

  • 避免使用在 API 上下文中会造成混乱的过于通用的名字,它们会导致对 API 概念的误解。应该选择能够精确描述概念的名字。这对于定义一阶 API 元素的名称尤其重要。因为名字与上下文相关,所以并没有明确的名字黑名单。Instance, info 和 service 是会产生问题的名字。应该选择能够明确表达出 API 概念(例:instance 表示什么的实例?)并且容易与其他相关概念有区分(例:alert 的意思是规则,信号还是通知?)的名字。

  • 谨慎使用会与常用编程语言中的关键字有冲突的名字。

产品名

产品名是指 API 的产品营销名称,例如 Google Calendar API。在 API、UI、文档、服务条款、结账单和商业合同中使用的产品名称 应该(should) 一致。

Google API 必须(must) 使用 Google 作为产品名的前缀,除非它们像 Gmail, Nest, Youtube 这种有不同的品牌。一般来说产品名 应该(should) 由产品和市场部门决定。

下表列出了所有相关 API 名称及其一致性的示例,有关各自名称及其约定的更多详细信息,请继续往下看。

| API 名 | 示例 |
| - | - |
| 产品名 | Google Calendar API |
| 服务名 | calendar.googleapis.com |
| 包名 | google.calendar.v3 |
| 接口名 | google.calendar.v3.CalendarService |
| 资源目录 | //google/calendar/v3 |
| API 名 | calendar |

服务名

服务名 应该(should) 是一个能够被解析为一个或多个网络地址的合法 DNS 名字。公有 Google API 的服务名遵循如下模式:xxx.googleapis.com。例如:谷歌日历的服务名是 calendar.googleapis.com

如果一个 API 由多个服务组成,它们 应该(should) 以能够提高可发现性的方法命名。一种方法是为这些服务名使用相同的前缀。例如服务 build.googleapis.combuildresults.googleapis.com 都是 Google Build API 的一部分。

包名

在 .proto 文件中定义的包名 应该(should) 与产品名和服务名相同。有版本号的包名 必须(must) 以版本号结尾。例如:

// Google Calendar API
package google.calendar.v3;

不与服务直接关联的抽象 API,例如 Google Watcher API 应该(should) 使用与产品名相同的 proto 包名:

// Google Watcher API
package google.watcher.v1;

在 .proto 文件中指定的 Java 包名 必须(must) 符合标准 Java 包名的前缀(com., edu., net. 等)。例如:

package google.calendar.v3;

// 指定 Java 包的名字,使用标准前缀 "com."
option java_package = "com.google.calendar.v3";

集合 ID

集合 ID 应该(should) 使用美式英语的、复数形式的、首字母小写的驼峰命名法,例如:events, childrendeletedEvents

接口名

为了避免和形如 pubsub.googleapis.com资源名混淆,术语 接口名 指的是在 .proto 文件中定义 service 时使用的名字:

// Library is the interface name.
service Library {
  rpc ListBooks(...) returns (...);
  rpc ...
}

你可以认为 服务名 是指一组 API 的具体实现,接口名 是指一个 API 的抽象定义。

接口名称 应该(should) 使用直观的名词,如 Calendar 或 Blob。不应该(should not) 与编程语言中已有的任何概念或运行时库冲突(如:File)。

接口名 与 API 中其他名字冲突时,应该为其加上前缀(如 ApiService)来进行区分。

方法名

在其 IDL 规范中,服务 可以(may) 定义与集合和资源上的方法相对应的一个或多个RPC方法。方法名 应该(should) 遵循像 VerbNoun 这样首字母大写的驼峰命名法的命名约定,其中名词(Noun)通常是资源类型。

| 动词(Verb) | 名词(Noun) | 方法名 | 请求信息 | 响应信息 |
| -| -| - | - | - |
| List | Book | ListBooks | ListBooksRequest | ListBooksResponse |
| Get | Book | GetBook | GetBookRequest | Book |
| Create | Book | CreateBook | CreateBookRequest | Book |
| Update | Book | UpdateBook | UpdateBookRequest | Book |
| Rename | Book | RenameBook | RenameBookRequest | RenameBookResponse |
| Delete | Book | DeleteBook | DeleteBookRequest | google.protobuf.Empty |

消息名

RPC 方法的请求与响应消息 应该(should) 以方法名分别加上 RequestResponse 的方式命名。除非方法的请求或响应类型如下:

  • 空消息(使用 google.protobuf.Empty

  • 资源类型

  • 代表一种操作的资源

枚举名

枚举类型的名字 必须(must) 使用首字母大写的驼峰命名法。

枚举值 必须(must) 以下划线分隔且字母全部大写的方式来命名(例如:CAPITALIZED_NAMES_WITH_UNDERSCORES)。每个枚举值 必须(must) 以分号而不是逗号结尾。第一个值 应该(should) 命名为 ENUM_TYPE_UNSPECIFIED,用于当没有明确指定枚举值时返回。

enum FooBar {
  // 第一个表示默认值,并且一定等于 0
  FOO_BAR_UNSPECIFIED = 0;
  FIRST_VALUE = 1;
  SECOND_VALUE = 2;
}

字段名

在 .proto 文件中定义的字段名 必须(must) 以下划线分隔且字母全部小写的方式来命名(例如:lower_case_underscore_separated_names)。这些名字会遵守各编程语言的命名约定来映射到生成的代码中。

重复字段名(Repeated field)

API 中的重复字段 必须(must) 使用合适的复数形式。这符合现有 Google API 的惯例以及外部开发人员的通常期望。

时间和间隔

应该(should) 使用 google.protobuf.Timestamp并且字段名 应该(should)time 结尾来表示独立于任一时区的时间点。例如 start_time, end_time

如果表示一个活动的时间,字段名 应该(should) 使用 verb_time 格式,如 create_time, update_time。避免使用动词的过去时形式,如 created_timelast_updated_time

应该(should) 使用 google.protobuf.Duration 来表示一个时间段。

message FlightRecord {
  google.protobuf.Timestamp takeoff_time = 1;
  google.protobuf.Duration flight_duration = 2;
}

如果因为遗留系统或兼容原因要使用整形来表示时间相关的字段(包含墙上时间、时间段、延迟),字段名 必须(must) 有如下形式:

xxx_{time|duration|delay|latency}_{seconds|millis|micros|nanos}
message Email {
  int64 send_time_millis = 1;
  int64 receive_time_millis = 2;
}

如果因为遗留系统或兼容原因要使用字符串来表示时间戳,字段名 不应该(should not) 包含任何单位后缀。应该(should) 使用形如 2014-07-30T10:43:17Z 的 RFC 3339 格式。

日期与时间

应该(should) 使用 google.type.Date 并且字段名以 _date 结尾来表示独立于时区与时间的日期。如果必须以字符串表示,应该使用形如 YYYY-MM-DD 的 ISO 8601 日期格式(例如 2014-07-30)。

应该(should) 使用 google.type.TimeOfDay 并且字段名以 _time 结尾来表示独立于时区与日期的时间。如果必须以字符串表示,应该使用形如 HH:MM:SS[.FFF] 的 ISO 8601 的 24 小时时间格式(例如 14:55:01.672)。

message StoreOpening {
  google.type.Date opening_date = 1;
  google.type.TimeOfDay opening_time = 2;
}

数量

以整形表示的数量 必须(must) 包含单位。

xxx_{bytes|width_pixels|meters}

如果表示物品的数量,字段名 应该(should) 使用 _count 做为后缀,如 node_count

List 过滤字段

如果 List 方法支持过滤资源,包含过滤表达式的字段 应该(should) 命名为 filter。例:

message ListBooksRequest {
  // 父资源名
  string parent = 1;

  // 过滤表达式
  string filter = 2;
}

List 响应

List 方法的响应消息中包含资源列表的字段名字 必须(must) 是资源名的复数形式。例如,方法 CalendarApi.ListEvents() 必须(must) 定义响应消息 ListEventsResponse,此消息中包含名为 events 的重复字段来用于返回资源列表。

service CalendarApi {
  rpc ListEvents(ListEventsRequest) returns (ListEventsResponse) {
    option (google.api.http) = {
      get: "/v3/{parent=calendars/*}/events";
    };
  }
}

message ListEventsRequest {
  string parent = 1;
  int32 page_size = 2;
  string page_token = 3;
}

message ListEventsResponse {
  repeated Event events = 1;
  string next_page_token = 2;
}

驼峰命名法

除了字段名和枚举值,在 .proto 文件中的所有定义 必须(must) 使用首字母大写的驼峰命名法

名字缩写

对于像 configspec 这种被软件工程师熟知的缩写,在 API 定义中 应该(should) 使用缩写而不是其完整形式,这会使代码便于读写。在正式的文档中 应该(should) 使用其完整形式。例如:

  • config (configuration)

  • id (identifier)

  • spec (specification)

  • stats (statistics)

查看其他章节


tailnode
1.2k 声望33 粉丝