6
6
表示范围的字段应该使用符合命名规范的半开半闭区间` [start_xxx, end_xxx) ` ,例如` [start_key, end_key) ` 或者` [start_time, end_time) ` 。半开半闭区间通常在C++ STL和Java的标准库里面被用到。API应该避免使用其他方法去代表范围,例如` (index, count) ` ,或者` [first, last] ` 。
7
7
8
8
## 资源标签
9
- 在面向资源的API里面,资源的结构通常由API定义。为了让客户端在资源上带上少量且简单的元数据 ,APIs应该使用在` google.api.LabelDescriptor ` 里面描述的` 资源标签设计模式 ` (resource label design pattern)。
9
+ 在面向资源的API里面,资源的结构通常由API定义。为了让客户端在资源上带上少量简单的元数据(举个例子,标记一台虚拟机资源为数据库服务器) ,APIs应该使用在` google.api.LabelDescriptor ` 里面描述的` 资源标签设计模式 ` (resource label design pattern)。
10
10
11
11
为了实现这一点,API设计应该在资源定义里面添加一个` map<string, string> ` 字段。
12
12
@@ -31,9 +31,9 @@ message Book {
31
31
32
32
为了支持` List ` 的分页操作,API应该:
33
33
34
- * 在方法的请求信息里面定义一个叫做` page_token ` 的` string ` 类型的字段。客户端用来向服务器请求关于集合某一页的内容。
35
- * 在方法的请求信息里面定义一个叫做` page_size ` 的` int32 ` 类型的字段。客户端用来指定服务器给其返回集合的最大资源个数。服务端可能会自己判断单页里面应该返回的资源个数,例如,当` page_size ` 的值为0时,服务端将会自己决定返回结果的最大资源数是多少。
36
- * 在` List ` 方法的响应信息中定义一个叫做` next_page_token ` 的` string ` 类型字段。这个字段用来指明用于接受下一页结果的token。如果这个字段的值是` "" ` ,这表明没有更多的请求结果了。
34
+ * 在方法的请求信息里面定义一个叫做` page_token ` 的` string ` 类型的字段。客户端用来向服务器请求关于集合某一页的内容。
35
+ * 在方法的请求信息里面定义一个叫做` page_size ` 的` int32 ` 类型的字段。客户端用来指定服务器给其返回集合的最大资源个数。服务端可能会自己判断单页里面应该返回的资源个数,例如,当` page_size ` 的值为0时,服务端将会自己决定返回结果的最大资源数是多少。
36
+ * 在` List ` 方法的响应信息中定义一个叫做` next_page_token ` 的` string ` 类型字段。这个字段用来指明用于接受下一页结果的token。如果这个字段的值是` "" ` ,这表明没有更多的请求结果了。
37
37
38
38
为了获取下一页的结果,客户端应该在下一个` List ` 请求时带上上一个请求的` next_page_token ` :
39
39
@@ -52,24 +52,34 @@ message ListBooksResponse {
52
52
}
53
53
```
54
54
55
- 在客户端在请求里面携带了除page token外的请求参数 (query parameters)的时候 ,如果参数与page token不一致,服务必须拒绝此请求。
55
+ 当客户端在请求里面携带了除page token以外的请求参数 (query parameters)时 ,如果参数与page token不一致,服务必须拒绝此请求。
56
56
57
- page token的内容应该是对web安全的BASE64编码后的protocol buffer,这样就不会有兼容性问题 。page token中存在敏感信息时,应该将其加密。服务端必须通过以下方法来防止通过篡改page token来获取敏感信息:
57
+ page token的内容应该是基于一个url安全的protocol buffer进行base64编码后的结果。这样在内容变动的时候就不会有兼容性问题 。page token中存在敏感信息时,应该将其加密。服务端必须通过以下方法来防止通过篡改page token来获取敏感信息:
58
58
59
- * 后续请求要重新指定请求参数
60
- * 在page token中仅引用服务端的状态
61
- * 在page token中加密并签名请求参数,并且在每次调用中对这些参数进行验证和鉴权 。
59
+ * 后续请求要重新指定请求参数
60
+ * 在page token中仅引用服务端的会话状态
61
+ * 在page token中加密并签名请求参数,并且在每次调用中对这些参数进行反复验证和鉴权 。
62
62
63
63
分页的实现可能会在一个叫做` total_size ` 的` int32 ` 类型的字段里面标明资源的总数。
64
64
65
65
## 列出子集合
66
- 某些时候,API需要让客户端可以在子资源里面进行 ` List/Search ` 。例如,API库可能有一个书架( shelves)集合,每个书架里面有一个书本(books)集合,假如某个客户想要在所有的书架里面搜索一本书,在这种情形下,最推荐的做法是在子资源里面使用标准的` List ` 方法,在父级集合里面使用集合的通配符 ` - ` 。对于这个API库的例子,我们可以使用以下的REST API请求:
66
+ 某些时候,API需要让客户端对子集合进行 ` List/Search ` 操作 。例如,图书馆(Library)API可能有一个书架( shelves)集合,每个书架里面有一个书本(books)集合,假如某个客户想要在所有的书架里面搜索一本书,在这种情形下,最推荐的做法是在子资源里面使用标准的` List ` 方法并为父级集合指定通配集合id ` "-" ` 。对于这个API库的例子,我们可以使用以下的REST API请求:
67
67
68
68
```
69
69
GET https://library.googleapis.com/v1/shelves/-/books/{id}
70
70
```
71
71
72
- 这个请求的响应资源名称一定要使用规范的名称,一定要是实际的父集合名称而不是一个` - ` 通配符。例如,以上请求应该返回一个类似于` shelves/shelf713/books/book8141 ` ,而不是` shelves/-/books.book8141 ` 的名称。
72
+ 提示:选择` "-" ` 替代` "*" ` 的原因是为了避免URL escaping。
73
+
74
+ ## 从子集合中获取唯一资源
75
+
76
+ 某些时候,有些子集合中的资源具有包括其父集合在内也唯一的标识符。在不知道哪一个父集合包含它的时候,允许通过` Get ` 来获取这个资源可能是有用的。在这种情况下,建议在该资源上使用标准` Get ` ,并为所有父集合指定通配集合id` "-" ` 。举个例子,在图书馆API中,我们可以使用以下的REST API请求,如果这本书在所有的书架上的所有书中是唯一的:
77
+
78
+ ```
79
+ GET https://library.googleapis.com/v1/shelves/-/books/{id}
80
+ ```
81
+
82
+ 在这个请求的响应中使用的资源名称一定要使用该资源的官方名称,为每一层父级集合使用实际的父级集合id而不是` "-" ` 。举个例子,以上请求返回的资源名称应该形如` shelves/shelf713/books/book8141 ` ,而非` shelves/-/books.book8141 ` 。
73
83
74
84
## 排列顺序
75
85
如果某一个API方法允许客户端指明列表结果的排序方式,请求消息应该包含以下字段:
@@ -78,20 +88,20 @@ GET https://library.googleapis.com/v1/shelves/-/books/{id}
78
88
string order_by = ...;
79
89
```
80
90
81
- 字符串的值应该遵循SQL语法:用逗号分隔的字段列表。例如:` ” foo,bar” ` 。每个字段默认按照升序排列,如果要指明某一个字段值按照降序排列,应该给这个字段添加` ” desc“ ` 后缀。例如:` ” foo desc,bar"` 。
91
+ 字符串的值应该遵循SQL语法:用逗号分隔的字段列表。例如:` " foo,bar" ` 。每个字段默认按照升序排列,如果要指明某一个字段值按照降序排列,应该给这个字段添加` " desc" ` 后缀。例如:` " foo desc,bar"` 。
82
92
83
- 多余的空格可以忽略,` ” foo,bar desc“ ` 和` ” foo , bar desc " ` 是相等的 。
93
+ 多余的空格可以忽略,` " foo,bar desc" ` 和` " foo , bar desc " ` 是等价的 。
84
94
85
95
## 请求校验
86
- 如果某个API方法有副作用,并且需要对请求进行校验来防止副作用的产生,这样的请求消息应该包含以下字段 :
96
+ 如果某个API方法有副作用,并且有必要在不产生副作用的情况下对请求进行校验,请求消息应该包含以下字段 :
87
97
88
98
```
89
99
bool validate_only = ...;
90
100
```
91
101
92
- 当此字段设置为` true ` 时,服务端一定不能执行任何有副作用的操作,而是对请求进行校验 。
102
+ 当此字段设置为` true ` 时,服务端一定不能执行任何有副作用的操作,并且只执行与完整请求一致的针对实现的校验 。
93
103
94
- 校验成功时必须返回 ` google.rpc.Code.OK ` ,并且使用相同请求信息的完整请求不应该返回 ` google.rpc.Code.INVALID_ARGUMENT ` 。注意,此请求可能还是会因为其他错误(比如` google.rpc.Code.ALREADY_EXISTS ` 或竞态条件)而失败。
104
+ 如果校验成功,必须返回 ` google.rpc.Code.OK ` ,并且使用相同请求信息的完整请求都不应该返回 ` google.rpc.Code.INVALID_ARGUMENT ` 。注意,此请求可能还是会因为其他错误(比如` google.rpc.Code.ALREADY_EXISTS ` 或竞态条件)而失败。
95
105
96
106
## 重复请求
97
107
对于网络API,幂等性是很重要的,因为当网络异常时它们能够安全地进行重试。然而一些API并不容易实现幂等性,例如需要避免不必要重复的创建资源操作。对于这类情况,请求信息应该包含一个唯一ID(例如UUID),这样服务端能够通过此ID来检测请求是否重复,保证请求只被处理一次。
@@ -105,11 +115,11 @@ string request_id = ...;
105
115
如果服务端检测到重复的请求,它应该给客户端返回之前成功的响应,因为之前那个响应客户端很有可能没有接收到。
106
116
107
117
## 枚举默认值
108
- 每个枚举必须从` 0 ` 开始定义,它 ` 应该 ` 在枚举值没有被显式指明时被使用。API ` 必须 ` 在文档中指明应该如何处理默认值 ` 0 ` 。
118
+ 每个枚举必须从` 0 ` 开始定义,它应该在枚举值没有被显式指明时使用。API必须在文档中指明应该如何处理默认值 ` 0 ` 。
109
119
110
- 如果有通用的默认行为,枚举值` 0 ` 就 ` 需要 ` 被使用 ,同时API文档也应该说明预期的行为。
120
+ 如果有通用的默认行为,枚举值` 0 ` 就应该被使用 ,同时API文档也应该说明预期的行为。
111
121
112
- 如果没有通用的默认行为,枚举值` 0``应该 ` 被命名为 ` ENUM_TYPE_UNSPECIFIED ` 并且要和` INVALID_ARGUMENT ` 错误一起使用。
122
+ 如果没有通用的默认行为,枚举值` 0 ` 应该被命名为 ` ENUM_TYPE_UNSPECIFIED ` 并且要和` INVALID_ARGUMENT ` 错误一起使用。
113
123
114
124
```
115
125
enum Isolation {
@@ -125,12 +135,12 @@ enum Isolation {
125
135
Isolation level = 1;
126
136
```
127
137
128
- ` 0 ` 值可以使用一个惯用名称来命名。例如,在没有错误码的情况下,可以使用惯用名称` google.rpc.Code.OK ` ,在这种情况下,` OK ` 语义上等同于枚举类型上下文的 ` UNSPECIFIED ` 。
138
+ ` 0 ` 值可以使用一个惯用名称来命名。例如,在没有错误码的情况下,可以使用惯用名称` google.rpc.Code.OK ` ,在这种情况下,` OK ` 语义上等价于枚举类型上下文的 ` UNSPECIFIED ` 。
129
139
130
- 若存在本质上合理和安全的默认值,这个值可以被用来作为 ` 0 ` 值。例如,在资源视图枚举中` BASIC ` 就是这种情况的 ` 0 ` 值。
140
+ 若存在本质上合理和安全的默认值,这个值就可以被用来作为 ` 0 ` 值。例如,在资源视图枚举中` BASIC ` 就是 ` 0 ` 值。
131
141
132
142
## 语法句法
133
- 在API设计中,有时候需要为某些特定的数据格式定义简单的语法,例如可接受的文本输入。为了在不同 API 中提供一致的开发体验和减少学习曲线,API 设计者 ` 必须 ` 使用扩展的Backus -Naur 表格( EBNF)变种句法来定义这些语法 。
143
+ 在API设计中,有时候需要为某些特定的数据格式定义简单的语法,例如可接受的文本输入。为了在跨APIs中提供一致的开发体验和减少学习曲线,API设计者们必须使用如下Extended Backus -Naur Form ( EBNF)句法变种来定义这些语法 。
134
144
135
145
```
136
146
Production = name "=" [ Expression ] ";" ;
@@ -147,10 +157,10 @@ Repetition = "{" Expression "}" ;
147
157
## 整数类型
148
158
在API设计中,不应该使用像` uint32 ` 和` fixed32 ` 这种无符号整型,这是因为一些重要的编程语言和系统(例如Java, JavaScript和OpenAPI)不能很好地支持它们,并且他们更容易导致溢出错误。另一个问题是,不同API很可能对同一个资源使用不同的数据类型(有符号和无符号整型)。
149
159
150
- 在大小和时间这种负数没有意义的类型中` 可以 ` 使用且仅可以使用` -1 ` 来表示特定的意义,例如文件结尾(EOF)、无穷的时间、无资源限额或未知的年龄。当在这种情况下使用负数时,` 必须 ` 在文档中明确说明其意义以防止混淆。如果语义不明显 ,API生产者也应该在文档中记录隐式默认值` 0 ` 表示的行为。
160
+ 在大小和时间这种负数没有意义的类型中` 可以 ` 使用且仅可以使用` -1 ` 来表示特定的意义,例如文件结尾(EOF)、无穷的时间、无资源限额或未知的年龄。当在这种情况下使用负数时,必须在文档中明确说明其意义以防止混淆。如果不够显而易见 ,API生产者也应该在文档中记录隐式默认值` 0 ` 表示的行为。
151
161
152
162
## 部分响应
153
- 客户端有时只需要响应信息中的特定子集。一些API平台提供了对部分响应的原生支持。Google API平台通过响应字段掩码来为其提供支持。对于任一REST API 调用,有一个隐式的系统query参数 ` $fields ` ,它是 ` google.protobuf.FieldMask ` 的JSON表示。在返回给客户端之前,响应消息会被` $fields ` 字段过滤。此行为是在API平台上的所有API方法上执行的 。
163
+ 客户端有时只需要响应信息中的特定子集。一些API平台提供了对部分响应的原生支持。Google API平台通过响应字段掩码来为其提供支持。对于任一REST API 调用,有一个隐式的系统query参数 ` $fields ` ,它是 ` google.protobuf.FieldMask ` 的JSON表示。在返回给客户端之前,响应消息会被` $fields ` 字段过滤。这个逻辑在API平台的所有API方法上都会被处理 。
154
164
155
165
```
156
166
GET https://library.googleapis.com/v1/shelves?$fields=name
@@ -161,10 +171,10 @@ GET https://library.googleapis.com/v1/shelves?$fields=name
161
171
162
172
参数满足以下条件:
163
173
164
- * ` 应该 ` 是枚举类型
165
- * ` 必须 ` 命名为` view `
174
+ * * 应该 * 是枚举类型
175
+ * * 必须 * 命名为` view `
166
176
167
- 枚举中的每个值定义了资源的哪部分(字段)在响应中会被返回。文档中 ` 应该 ` 明确指定每个 ` view ` 值会返回什么。
177
+ 枚举中的每个值定义了资源的哪部分(字段)在响应中会被返回。文档中应该明确指定每个 ` view ` 值会返回什么。
168
178
169
179
```
170
180
package google.example.library.v1;
@@ -191,7 +201,7 @@ enum BookView {
191
201
message ListBooksRequest {
192
202
string name = 1;
193
203
194
- // 指定返回图书资源的哪些部分
204
+ // 指定图书资源的哪些部分应该被返回
195
205
BookView view = 2;
196
206
}
197
207
```
@@ -204,7 +214,7 @@ GET https://library.googleapis.com/v1/shelves/shelf1/books?view=BASIC
204
214
可以在[ 标准方法] ( Standard_Methods.md ) 一章中查看更多关于定义方法、请求和响应的内容。
205
215
206
216
## ETags
207
- ETag是一个不透明的标识符,允许客户端进行条件性请求。为了支持 ETag,API ` 应该 ` 在资源定义中包含一个字符串字段 ` etag ` ,它的语义 ` 必须 ` 与ETag的常用用法相匹配 。通常,` etag ` 包含由服务器计算出的资源指纹。更多详细信息,请参阅 [ 维基百科] ( https://en.wikipedia.org/wiki/HTTP_ETag ) 和[ RFC 7232] ( https://tools.ietf.org/html/rfc7232#section-2.3 ) 。
217
+ ETag是一个不透明的标识符,允许客户端进行条件性请求。为了支持 ETag,API应该在资源定义中包含一个字符串字段 ` etag ` ,它的语义必须与ETag的常用用法相匹配 。通常,` etag ` 包含由服务器计算出的资源指纹。更多详细信息,请参阅 [ 维基百科] ( https://en.wikipedia.org/wiki/HTTP_ETag ) 和[ RFC 7232] ( https://tools.ietf.org/html/rfc7232#section-2.3 ) 。
208
218
209
219
ETags可以是强验证的或弱验证的,其中弱验证的ETag以` W/ ` 为前缀。在这种情况下,强验证意味着具有相同ETag的两个资源具有每字节都相同的内容和相同的额外字段(例如,Content-Type),同时也意味着强验证的ETag允许对稍后组装的部分响应进行缓存。
210
220
@@ -219,7 +229,7 @@ ETags可以是强验证的或弱验证的,其中弱验证的ETag以`W/`为前
219
229
W/"1a2b3c4d5ef"
220
230
```
221
231
222
- 值得注意的是引号也是ETag值的一部分,而且为了遵循 [ RFC 7232] ( https://tools.ietf.org/html/rfc7232#section-2.3 ) 它们一定要被表示出来。这就意味着ETags的JSON表示一定要对引号进行转义。例如ETags在JSON资源的表示是:
232
+ 值得注意的是引号也是ETag值的一部分,而且为了遵循[ RFC 7232] ( https://tools.ietf.org/html/rfc7232#section-2.3 ) 它们一定要被表示出来。这就意味着ETags的JSON表示一定要对引号进行转义。例如ETags在JSON资源的表示是:
223
233
224
234
```
225
235
// 强验证
@@ -230,16 +240,16 @@ W/"1a2b3c4d5ef"
230
240
231
241
ETags中允许的字母:
232
242
233
- * 可打印的ASCII码
234
- * RFC 2732中指定的非ASCII码,不过他们对开发者来说不是很友好
235
- * 没有空格
236
- * 除了上面的双引号,不能有别的双引号
237
- * RFC 7232中推荐不能使用反斜线以防止和转移符混淆
243
+ * 可打印的ASCII码
244
+ * RFC 2732中指定的非ASCII码,不过他们对开发者来说不是很友好
245
+ * 没有空格
246
+ * 除了上面的双引号,不能有别的双引号
247
+ * RFC 7232中推荐不能使用反斜线以防止和转移符混淆
238
248
239
249
## 输出字段
240
- API可能希望将由客户端提供的输入字段和只由服务端在特定资源上返回的输出字段进行区分。对于仅输出的字段,` 应该 ` 记录该字段的属性 。
250
+ API可能希望将由客户端提供的输入字段和只由服务端在特定资源上返回的输出字段进行区分。对于仅输出的字段,应该记录该字段的属性 。
241
251
242
- 请注意,如果客户端在请求中设置了仅输出(output only)字段,或者客户端使用仅输出字段指定了一个 ` google.protobuf.FieldMask ` ,则服务器 ` 必须 ` 接受该请求而不能报错。这意味着服务器 ` 必须 ` 忽略仅输出字段的存在及其任何指示 。这个建议的原因是因为客户端通常会将服务器返回的资源重用为另一个请求的输入,例如一个获取到的` Book ` 将在` UPDATE ` 方法中被再次使用。如果要验证仅输出字段,客户端需要做清除输出字段的额外工作。
252
+ 请注意,如果客户端在请求中设置了仅输出(output only)字段,或者客户端对仅输出字段指定了一个 ` google.protobuf.FieldMask ` ,则服务器必须接受该请求而不能报错。这意味着服务器必须忽略仅输出字段的存在及其任何指示 。这个建议的原因是因为客户端通常会将服务器返回的资源重用为另一个请求的输入,例如一个获取到的` Book ` 将在` UPDATE ` 方法中被再次使用。如果要验证仅输出字段,客户端需要做清除输出字段的额外工作。
243
253
244
254
```
245
255
message Book {
@@ -250,9 +260,9 @@ message Book {
250
260
```
251
261
252
262
## 单例资源
253
- 单例资源使用在父节点只有一个资源实例的情况下(如果没有父资源,则其存在整个API中) 。
263
+ 单例资源被使用于整个父级资源范围内(如果没有父级资源,则是整个API范围内)只有一个资源实例的情况下 。
254
264
255
- 标准` Create ` 和` Delete ` 方法不能被用于单例资源上;单例会在其父资源创建或删除的时候被隐式创建或删除(或者在其没有父资源的前提下,会隐式存在)。资源 ` 必须 ` 可以通过标准的 ` Get ` 和` Update ` 方法被访问到。
265
+ 标准` Create ` 和` Delete ` 方法不能被用于单例资源上;单例会在其父资源创建或删除的时候被隐式创建或删除(或者在其没有父资源的前提下,会隐式存在)。资源必须可以通过标准的 ` Get ` 和` Update ` 方法被访问到。
256
266
257
267
例如,` User ` 资源的API应该对外暴露一个作用于单个用户` Setting ` API:
258
268
@@ -288,7 +298,7 @@ message UpdateSettingsRequest {
288
298
}
289
299
```
290
300
291
- ## 流媒体半关闭
292
- 对于任何双向API或客户端流式APIs,服务器都 ` 应该 ` 依赖由RPC系统提供的客户端启动的半关闭来完成客户端流。 没有必要定义一个明确的完成消息。
301
+ ## 流的半关闭
302
+ 对于任何双向API或客户端流式APIs,服务器都应该依赖由RPC系统提供的客户端启动的半关闭来完成客户端流。 没有必要定义一个明确的完成消息。
293
303
294
304
客户需要在半关闭之前发送的任何信息都必须定义为请求消息的一部分。
0 commit comments