1. 标准方法
我们定义五个标准方法,包括了List, Get, Create, Update, and Delete。很多不同类型的API都拥有非常类似的语义,把它们归纳为标准方法能够显著降低复杂度并提高一致性,我们实行的大部分API属于标准方法。标准方法更容易学习和使用。 以下表格描述了如何将标准方法映射为REST方法,也就是所谓的CRUD方法:
方法 | HTTP方法映射 | HTTP请求体 | HTTP返回体 |
---|---|---|---|
List | GET <集合URL>集合URL> | 空 | 资源 列表 |
Get | GET <资源URL>资源URL> | 空 | 资源 |
Create | POST <集合URL | 资源 | 资源 |
Update | PUT or PATCH <资源URL>资源URL> | 资源 | 资源 |
Delete | DELETE <资源URL>资源URL> | 空 | 空 |
Delete方法如果并没有立刻删除响应的资源(例如创建一个耗时删除操作或者更新标识),它的响应应该包括耗时操作或更新后的资源。
如果请求无法在单个API调用时间段内完成时,标准方法可以返回一个耗时操作。
1.1. List
List方法接受一个集合名,零或者多个参数,根据输入返回相应的资源列表。它也经常被用作搜索资源。
List适用于量有限且无缓存的单一集合数据查询;若需要更广的应用,应该用自定义方法Search。
批量获取(如接受多个资源ID并返回每个ID对象的方法)应该使用自定义方法BatchGet实现,而不是List方法。但如果你已经有了提供相似功能的List方法,你也可以继续使用。如果你使用自定义的BatchGet方法,应该确保它映射为HTTP GET方法。
使用常见模式:分页,结果排序。
适用命名约定:过滤字段,结果字段。
HTTP 映射
- List方法必须使用HTTP Get方法。
- 请求消息字段接收资源名称集合,而相关资源应该映射为URL路径。如果集合名称映射到URL路径,URL模板中的最后一段(即集合ID)必须为文字。
- 其他所有请求消息字段应当映射为URL请求参数
- 没有请求体,即API配置中不应该声明请求体
- 返回体应该包含资源集合以及可选的元数据
1.2 Get
Get方法接受一个资源名,零到多个参数,返回指定的资源。
HTTP 映射
- Get方法必须使用HTTP Get方法。
- 接收资源名称的请求消息字段(可多个)应该映射到URL路径中。
- 其他所有请求消息字段应当映射到URL查询参数中。
- 无请求体,即API配置中绝对不可以出现请求体声明。
- 返回资源应当映射到返回体中
1.3. Create
Create方法接受一个集合名,一个资源,并且有零或多个参数;然后在相应集合中创建新的资源,最后返回新创建的资源。
如果API支持创建资源,那么它应该有Create方法用于创建各种类型的资源。
HTTP 映射
- Create方法必须使用HTTP POST方法。
- 请求消息应该有一个名为parent的字段,以接受父级资源名,当前资源将在父资源下创建。
- 其他所有请求消息字段应当映射到URL查询参数中。
- 请求可以包括一个名为_id的字段,以允许调用方选择客户端分配的ID,此字段必须映射为URL查询参数。
- 包含资源的请求消息字段应该映射到请求体中。
- 返回的资源应当映射到整个返回体中。
如果Create方法支持客户端指定资源名,并且相应资源已经存在;那么它应该返回错误(推荐使用google.rpc.Code.ALREADY_EXISTS错误代码),或使用其它服务器指定的资源名:文档中需要清晰说明被创建的资源名可能跟传入的资源名不同。
1.4. Update
Update方法接受包括一个资源的请求消息,并且有零或多个参数。它更新相应资源以及它的属性;返回更新后的资源。
可变的资源属性应当被Update方法修改,除非属性包含资源的名称或者父资源。所有的重命名或者移动资源操作一定不能用Update方法,这些应当用自定义方法处理。
HTTP 映射
- 标准的Update方法应该支持部分资源更新,并使用 HTTP PATCH方法以及名为update_mask的FieldMask字段。
- 如果Update方法需要更高级的修复语义,比方说给重复字段增补新值,那么应该使用自定义方法。
- 如果Update方法仅支持完整的资源更新,它必须使用HTTP PUT;但是强烈不推荐这么做,因为这会造成添加新资源字段时的兼容性问题。
- 接受资源名的字段必须映射到URL路径中;字段也可以包含在资源消息中
- 包含资源的请求消息中字段必须映射到请求体中。
- 其他所有请求消息字段必须映射到URL查询参数中。
- 返回的结果必须是更新后的资源。
如果API允许客户端指定资源名,服务器可以允许客户端指定一个不存在的资源名并创建新的资源。否则,使用不存在的资源名时Update方法应该报错。如果不存在资源是唯一的错误条件,那么错误码应该用NOT_FOUND。
API如果有Update方法,并且支持资源创建的话,就应该提供Create方法;以避免调用者误以为Update方法是创建资源的唯一方式。
1.5. Delete
Delete方法接受一个资源名,零或多个参数;然后删除,或者安排删除相应的资源。Delete方法应该返回google.protobuf.Empty。
注意API不应该依赖于Delete方法返回的任何信息,因为它不能被反复调用(译者注:因为资源可能已经被删除了)。
HTTP 映射
- Delete方法必须使用HTTP DELETE方法
- 对应于资源名称的请求消息字段(可多个)应该绑定到URL路径中。
- 其他所有请求消息字段应当映射到URL查询参数中。
- 无请求体,即API配置中绝对不可以出现请求体声明。
- 如果Delete方法立刻删除除资源,它应该返回空。
- 如果Delete方法开启了一个耗时操作,它应该返回这个耗时操作
- 如果Delete方法仅是把资源标记为删除,它需要返回更新后的资源
调用Delete方法必须是幂等的,但返回值可以不同。任意次数的Delete请求应当使得一个资源(最终)被删除,但只有第一次请求获得成功的返回值,后续的请求应当返回google.rpc.Code.NOT_FOUND.
1.6. 自定义方法
自定义方法指的是五个标准方法之外的API方法。他们应当仅用于标准方法不易表达的功能。一般而言,API设计者应当尽可能优先考虑使用标准方法,而不是自定义方法。标准方法相对更简单,定义完善的语义,并且开发者也更加熟悉;这使标准方法更易用,并且使用者更难犯错。使用标准方法的另一个优势是API平台会有更好的支持,如计费、错误处理、日志、监控等等。
自定义方法可以跟资源、集合或者服务关联。它可以接受任意请求,并返回任意结果;并支持流式的请求与结果。
HTTP映射
对于自定义方法,它们应该使用以下形式的HTTP映射
https://service.name/v1/some/resource/name:customVerb
使用:而不是/符号去分隔自定义动词跟资源名,可以让我们支持任意路径。比方说取消删除一个文件可以映射为POST /files/a/long/file/name:undelete
选择HTTP映射时,应当应用以下准则:
- 自定义方法应该使用HTTP POST,因为它含有最灵活的语义。
- 自定义方法可以使用其它HTTP动词,但方法需要遵从该动词的标准HTTP语义。
- 请注意,使用HTTP GET的自定义方法必须是幂等并且无副作用。比方说,支持资源特定视图的自定义方法可以用HTTP GET。
- 对应于资源名或者资源集合名的请求消息字段应当映射为URL路径。
- URL路径必须以冒号 + 自定义动词结尾。
- 如果HTTP动词允许请求体消息(如 POST, PUT, PATCH, 或者其它HTTP动词),那么自定义方法的HTTP配置必须使用body: “*“,并且其它所有剩余的请求消息自动应当映射到请求体中。
- 如果HTTP动词不允许请求体消息(如 GET, DELETE),那么自定义方法的HTTP配置就绝不可以使用body,并且其它所有剩余的请求消息字段自动应当映射到URL查询参数中。。
常见自定义方法
API设计者应当考虑使用以下一些常见或者有用的自定义方法名;而不是直接定义新的名字,以提高不同API之间的一致性。
方法名 | 自定义动词 | HTTP动词 | 备注 |
---|---|---|---|
Cancel | :cancel | POST | 取消一个未完成的操作(构建,计算等等) |
BatchGet | :batchGet | GET | 批量获取多个资源 |
Move | :move | POST | 将一个资源从一个父级移到另一个 |
Search | :search | GET | List的语义不足够时,搜索获取数据 |
Undelete | :undelete | POST | 恢复之前删除的数据;推荐的数据的保留时间是30天。 |
2. 标准字段
本节描述了在需要类似概念时应使用的一组标准消息字段定义。 这将确保相同的概念在不同的API上具有相同的名称和语义。
字段名 | 类型 | 描述 |
---|---|---|
name | string | name字段应该包含相对资源名 |
parent | string | 对于资源定义和List/Create请求,parent字段应包含父级相对资源名 |
create_time | Timestamp | 一个实体的创建时间戳 |
update_time | Timestamp | 一个实体的最后更新时间戳;注意update_time会被create/patch/delete等操作更新 |
delete_time | Timestamp | 实体的删除时间戳,仅当支持保留时。 |
time_zone | string | 时区名,它应该符合IANA时区标准,如”America/Los_Angeles”。请参阅 https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. |
region_code | string | 位置的Unicode国家/地区代码(CLDR),例如“US”和“419”。请参阅 http://www.unicode.org/reports/tr35/#unicode_region_subtag。 |
language_code | string | BCP-47语言代码,如“en-US”或“sr-Latn”。请参阅http://www.unicode.org/reports/tr35/#Unicode_locale_identifier。 |
display_name | string | 一个实体显示的名称 |
title | string | 实体的正式名称,例如公司名称。 它应该被视为正规版本的display_name |
description | string | 一个实体的详细文字描述 |
filter | string | List方法的标准过滤参数 |
query | string | 应用于Search方法的(也就是说 :search)过滤参数 |
page_token | string | List请求的数据分页令牌 |
page_size | int32 | List请求的数据分页大小 |
total_size | int32 | 列表中的总条目数,不考虑分页 |
next_page_token | string | List返回结果中下一个分页的令牌。它应该在后续请求中传递为page_token参数;空值意味着没有更多数据 |
request_id | string | 用于检测重复请求的唯一字符串id |
resume_token | 用于恢复流式传输请求的隐含令牌 | |
labels | map | 表示云资源的标签 |
deleted | bool | 如果资源允许取消删除,则它必须有deleted字段表示资源是否已被删除 |
show_deleted | bool | 如果资源允许取消删除,相应的List方法必须有一个show_deleted字段,以便客户端发现已删除的资源。 |
validate_only | bool | 如果为true,则表示给定的请求仅需要被检验,而不是被执行。 |