Read the latest article and comment on Notion.
-
API 的大致分类
- Standard methods: GET / List / Create / Update / Delete
- Standard methods 和其他methods 的 batch operations
- Standard methods 和其他methods 的 long-running operations
- Jobs 接口
- Import and export 数据接口
- item method / collection method / db method / stateless method
特殊接口
- Revision 接口,一个资源的历史记录,之所以叫’revision’,是为了和API 的‘version’ 区分开
-
get,记得在返回的name 里加上revision id。
-
tag,给一个revision 加上human readable 的标签,之后revision id 和tag 都能用来get revision。
-
list
-
commit,基于最新版本的resource 创建revision,可以在一些条件下自动创建,也可以开放出来把时机判断交给用户。
-
rollback,把某个revision 设置成线上最新的数据。
-
delete。可以导致线上resource 变化,但是不能导致resource 被删除,当被删除的revision 是最后一个revision 时,应拒绝请求。
-
child revision。适当考虑一个资源下的某个子资源也有revision 的需求。
-
- Purge 接口,当需要删除的数据量级超过Batch Delete 语义,考虑使用Purge
- 支持使用
filter
来筛选出更多的资源,但是因为数量过大没必要返回。 - 只有当 request 的
force == true
时才执行删除。 - response 要返回
purge_count
- 当request
force == false
时,返回purge_count
和约100个purge_sample
- 支持使用
-
AIPs 体现出的设计原则
**方便外界调用方的使用。**一些原则对内部API 要求过高了。
- 统一规范:doc 详细cover 了很多细节。
- 比如每个resource response 的第一个field 都得是 canonical name,无论request。
- 对于collections response,则是
parent
,不是name
。
- 对于collections response,则是
- 分页只返回
page_token
不返回offset
- token 可以代表更多信息。
- 防止用户解析分页的内部逻辑,给接口更新带来灵活性。
- token 一般3天后过期
order_by
字段也用string ,保证灵活性。- update 只能用
PATCH
,PUT
有可能会破坏兼容性。PUT
代表全替换,有时候客户端觉得一个对象的fields 是旧的 F F F,但可能服务端已经是新的 F ′ F^{'} F′了, 这时就出错了。
- 强一致性就用
etag
,服务端生成下放给客户端,客户端更新时带上etag
(乐观锁 - 幂等性就用
request_id
,客户端生成发给服务端,表示相关的请求是同一个,请求幂等。 - 预计执行时间超过10秒的方法返回query id而不是结果,保持运行结果30天内可查询。
start
和end
表示[, )
数组;first
和last
表示[, ]
数组。- 错误信息不应该假设用户知道API 的底层实现细节,brief but actionable。
- 如果需要更多的信息,考虑提供一个link where a reader can get more information or ask questions to help resolve the issue.
- 错误信息应该提供足够机器理解的数据,如果没有。改变错误信息的
string message
也应该被考虑为 a backwards-incompatible change. - 尽量不要提供部分错误部分正确的response,会给用户解析带来困难。
state
而不是status
,和HTTP 状态做区分。
- 比如每个resource response 的第一个field 都得是 canonical name,无论request。
- 在全面的规则外侧建立灵活性:
- id 可以有alias,例如用
me
替代当前用户的id。 - enum 只适用于枚举值变化不频繁的情况,变化频繁还是用string。
- 以及只要变化频繁都更使用string,没有过多的强类型限制。
- 没有必要说update 需返回被更新对象的所有field,如果一个field计算昂贵,那也没必要在更新完就计算,但是update masks 里面cover 的field 还是一定要返回。
- Partial response 可以用 view enumeration (事先定义好不同的view 选项,比如
BASIC
或者FULL
),也可以用read masks。
- id 可以有alias,例如用
- 保证安全调用
- update 尽量只更新对象的数据本身,side effects should be triggered by custom methods.
- 删除要用
force
field,没有force == true
就要执行足够多的安全检查。 - 对一个数据的collection field 更新需考虑添加单独的
Add
和Remove
方法,直接替换数组容易导致错误,或者用etag
保证强一致性。 - 对 singleton resources (一个parent 只有一个的resource),不可以有
Create
List
Delete
方法,这些应该让parent 负责。 validate_only
字段,为写接口提供dry run 语义。- soft delete,
show_deleted
字段 和相应的Undelete
接口。- 还可以加上30天后自动删除的机制。
- API 设计关注结果,命名尽量抛弃不必要的修饰词,力求直观好记,对使用方友好。
- 在
control plane
和data plane
之间用不同资源划清楚边界。- Control plane operations are responsible for managing the lifecycle of resources. (row level)
- Data plane operations are responsible for managing the content of resources. (DB level)
- 统一规范:doc 详细cover 了很多细节。
-
提供了一些magic number “经验之谈”
- 分页token 一般三天后过期
- 预计执行时间超过10秒的方法返回query id而不是结果,保持运行结果30天内可查询。
- soft delete 在30天后才真正删除。
- Beta 版本转成stable 版的时间一般是90天。
-
附:AIPs 的命名规范
Repeated fields
Repeated fields must use the proper plural form, such as
books
orauthors
. On the other hand, non-repeated fields should use the singular form such asbook
orauthor
. This implies that resource names should use the singular form as well, since the field name should follow the resource name (e.g., userepeated Book books
, notBooks books = 1
).Prepositions
Field names should not include prepositions (such as “with”, “for”, “at”, “by”, etc). For example:
error_reason
(notreason_for_error
)author
(notwritten_by
)
It is easier for field names to match more often when following this convention. Additionally, prepositions in field names may also indicate a design concern, such as an overly-restrictive field or a sub-optimal data type. This is particularly true regarding “with”: a field named
book_with_publisher
likely indicates that the book resource may be improperly structured and worth redesigning.Adjectives
For consistency, field names that contain both a noun and an adjective should place the adjective beforethe noun. For example:
collected_items
(notitems_collected
)imported_objects
(notobjects_imported
)
Booleans
Boolean fields should omit the prefix “is”. For example:
disabled
(notis_disabled
)required
(notis_required
)
String vs. bytes
When using
bytes
, the contents of the field are base64-encoded when using JSON on the wire. Services should usebytes
when there is a need to send binary contents over the wire, and should not ask the user to manually base64-encode a field into astring
field.URIs
Field names representing URLs or URIs should always use
uri
rather thanurl
. This is because while all URLs are URIs, not all URIs are URLs. Field names may use a prefix in front ofuri
as appropriate.Reserved words
Field names should avoid using names that are likely to conflict with keywords in common programming languages, such as
new
,class
,function
,import
, etc. Reserved keywords can cause hardship for developers using the API in that language.Conflicts
Messages should not include a field with the same name as the enclosing message (ignoring case transformations). This causes conflicts when generating code in some languages.
Display names
Many resources have a human-readable name, often used for display in UI. This field should be called
display_name
, and should not have a uniqueness requirement.If an entity has an official, formal name (such as a company name or the title of a book), an API may use
title
as the field name instead. Thetitle
field should not have a uniqueness requirement.Quantities
Quantities with a clear unit of measurement (such as bytes, miles, and so on) must include the unit of measurement as the suffix. When appropriate, units should use generally accepted abbreviations (for example,
distance_km
rather thandistance_kilometers
).// A representation of a non-stop air route. message Route { // The airport where the route begins. string origin = 1; // The destination airport. string destination = 2; // The distance between the origin and destination airports. // This value is also used to determine the credited frequent flyer miles. int32 distance_miles = 3; }
If the quantity is a number of items (for example, the number of nodes in a cluster), then the field shoulduse the suffix
_count
(not the prefixnum_
):// A cluster of individual nodes. message Cluster { // The number of nodes in the cluster. int32 node_count = 1; }
Note: Fields must not use unsigned integer types, because many programming languages and systems do not support them well.
Resource names and IDs
name
Every resource must have a
string name
field, used for the resource name (AIP-122), which should be the first field in the resource.parent
The
string parent
field refers to the resource name of the parent of a collection, and should be used in mostList
(AIP-132) andCreate
(AIP-133) requests.uid
The output only
string uid
field refers to a system-assigned, unique identifier for a resource. When provided, this field should be a UUID4. Declarative-friendly resources should include this field.Other names
display_name
The
string display_name
field must be a mutable, user-settable field where the user can provide a human-readable name to be used in user interfaces. Declarative-friendly resources should include this field.Display names should not have uniqueness requirements, and should be limited to <= 63 characters.
title
The
string title
field should be the official name of an entity, such as a company’s name. This is a more formal variant ofstring display_name
.given_name
The
string given_name
field must refer to a human or animal’s given name. Resources must not usefirst_name
for this concept, because the given name is not placed first in many cultures.family_name
The
string family_name
field must refer to a human or animal’s family name. Resources must not uselast_name
for this concept, because the family name is not placed last in many cultures.Timestamps
create_time
The output only
google.protobuf.Timestamp create_time
field must represent the timestamp when the resource was created. This may be either the time creation was initiated or the time it was completed. Declarative-friendly resources should include this field.update_time
The output only
google.protobuf.Timestamp update_time
field must represent the timestamp when the resource was most recently updated. Any change to the resource made by users must refresh this value; changes to a resource made internally by the service may refresh this value. Declarative-friendly resources should include this field.delete_time
The output only
google.protobuf.Timestamp delete_time
field must represent the timestamp that a resource was soft deleted. This may correspond to either the time when the user requested deletion, or when the service successfully soft deleted the resource. If a resource is not soft deleted, thedelete_time
field must be empty.Resources that support soft delete (AIP-164) should provide this field.
expire_time
The
google.protobuf.Timestamp expire_time
field should usually represent the time when a soft deleted resource will be purged from the system. It may be used for similar forms of expiration as described in AIP-214. Resources that support soft delete should include this field.In some situations, it can be difficult to provide an exact
expire_time
value, because of implementation dependencies. Services may provide anexpire_time
value that is inexact, but the resource must not be expired from the system before that time.Resources that support soft delete (AIP-164) should provide this field.
Descriptions
- What is it?
- How do you use it?
- What does it do if it succeeds? What does it do if it fails?
- Is it idempotent?
- What are the units? (Examples: meters, degrees, pixels)
- What are the side effects?
- What are common errors that may break it?
- What is the expected input format?
- What range of values does it accept? (Examples:
[0.0, 1.0)
,[1, 10]
)- Is the range inclusive or exclusive?
- For strings, what is the minimum and maximum length, and what characters are allowed?
- If a value is above the maximum length, do you truncate or send an error?
- Is it always present? (Example: “Container for voting information. Present only when voting information is recorded.”)
- Does it have a default setting? (Example: “If
page_size
is omitted, the default is 50.”)