[Design]-API设计指南

Posted 飞鹰技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Design]-API设计指南相关的知识,希望对你有一定的参考价值。

面向资源设计REST API设计流程资源方法资源命名资源ID标准方法List自定义标准字段错误错误消息HTTP映射状态码命名约定服务名称包名称方法名称

本篇摘选自《Google API Design Guide》。 

面向资源设计

API设计要遵循简单、一致、易用的原则。

在REST架构中资源与方法可视为API的动词名词;在HTTP REST API中,资源名称对应于URL,而方法对应于HTTP中的GET/POST/PUT/PATCH/DELETE


REST API

一组REST API被建模为一组可独立寻址的资源,并通过资源名称被引用,通过一组方法来操作。

设计流程

面向资源的API设计可使用以下步骤:

  • 确定API提供什么类型的资源;

  • 确定资源间的关系;

  • 根据资源类型和关系确定资源命名方案;

  • 明确资源的schema;

  • 给资源添加最少的方法集;

资源

面向资源的API通常被建模为一个资源层次结构;每个节点可以是一个简单资源或一组资源。资源组为:

  • 资源组包含相同类型的一系列资源;

  • 资源有相同的状态,可以有零个或多个子资源。

方法

典型的面向资源的API通过少量方法暴露大量资源;常用的有List/Get/Create/Update/Delete


资源命名

资源名称是资源的标识符,每个资源必须有其唯一的资源名称。资源名称由资源ID本身、父资源的ID和资源对应的API服务名称组成。

资源组是一种特殊的资源,它包含一组相同类型的子资源。资源名称使用组ID和资源ID分层组织,以斜杠/分割。

如一个存储服务有一组bucket,每一个bucket有一组objects

API资源名称 组ID 资源ID 组ID 资源ID
//storage.googleapis.com /buckets bucket-id objects object-id

资源ID

资源ID也会出现在客户端库里,需满足以下要求:

  • 必须是有效的C/C++标识符;

  • 必须是驼峰命名的(组资源名称要使用复数形式),首字母小写;

  • 必须使用清晰建模的英文词语;

  • 避免或者限定过于笼统的词语:如未限定的Element、Item、Value、Type等。


标准方法

标准方法映射为REST方法:

方法 HTTP 方法映射 HTTP 请求体 HTTP 返回体
List GET <集合URL> 资源* 列表
Get GET <资源URL> 资源*
Create POST <集合URL> 资源 资源*
Update PUT or PATCH <资源URL> 资源 资源*
Delete DELETE <资源URL> 空**

List

List方法接受一个集合名,零或多个参数,根据输入返回相应的资源列表;适用于数量有限且无缓存的单一集合数据查询。更广泛的应用,应自定义方法Search

批量获取(接受多个资源ID,并返回对应的每个对象)应使用自定义方法BatchGet,且映射为HTTP Get方法。

自定义

自定义方法命名(非标准方法不能满足要求时,要使用一些常见或有用的自定义方法):

方法名 自定义动词 HTTP动词 备注
Cancel :cancel POST 取消一个未完成的操作(构建,计算等等)
BatchGet :batchGet GET 批量获取多个资源
Move :move POST 将一个资源从一个父级移到另一个
Search :search GET List的语义不足够时,搜索获取数据
Undelete :undelete POST 恢复之前删除的数据;推荐的数据的保留时间是30天。


标准字段

标准消息字段定义:

字段名 类型 描述
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 string 用于恢复流式传输请求的隐含令牌
labels map\ 表示云资源的标签
deleted bool 如果资源允许取消删除,则它必须有deleted字段表示资源是否已被删除
show_deleted bool 如果资源允许取消删除,相应的List方法必须有一个show_deleted字段,以便客户端发现已删除的资源。
validate_only bool 如果为true,则表示给定的请求仅需要被检验,而不是被执行。


错误

当API方式错误时,返回一个错误状态给客户端:

message Status {
 // A simple error code that can be easily handled by the client.
 int32 code = 1;
 // A developer-facing human-readable error message. It should
 // both explain the error and offer an actionable resolution to it.
 string message = 2;
 // Additional error information that the client code can use to handle
 // the error, such as retry delay or a help link.
 repeated google.protobuf.Any details = 3;
}

错误代码应统一定义。

错误消息

错误消息应帮助用户方便、快速地理解和解决API错误,编写错误消息时,一般应遵循:

  • 不要假定用户是API专家:用户可能是客户端开发人员、操作人员、IT人员或程序最终用户;

  • 不要假定用户了解服务实现或错误上下文;

  • 若可能,应构造错误消息,以便技术用户可以响应错误并更正;

  • 保持错误消息的简洁:需要时可提供链接,帮助用户反馈或获取更新信息。


HTTP映射

HTTP的错误使用以下JSON格式表示:

{
 "error": {
   "code": 401,
   "message": "Request had invalid credentials.",
   "status": "UNAUTHENTICATED",
   "details": [{
     "@type": "type.googleapis.com/google.rpc.RetryInfo",
     ...
  }]
}
}
字段 描述
error 用于向后兼容Google API客户端库的额外层。它使用JSON来标示以便人类阅读。
code Status.code的HTTP状态代码映射
message 这对应于Status.message
status 这对应于Status.status
details 这对应于Status.details

状态码

常见错误码与其原因简短说明:

HTTP RPC 描述
200 OK 没有错误
400 INVALID_ARGUMENT 客户端指定了无效的参数。检查错误消息和错误详细信息以获取更多信息。
400 FAILED_PRECONDITION 请求不能在当前系统状态下执行,例如删除非空目录。
400 OUT_OF_RANGE 客户端指定了无效的范围。
401 UNAUTHENTICATED 由于遗失,无效或过期的OAuth令牌而导致请求未通过身份验证。
403 PERMISSION_DENIED 客户端没有足够的权限。这可能是因为OAuth令牌没有正确的范围,客户端没有权限,或者客户端项目尚未启用API。
404 NOT_FOUND 找不到指定的资源,或者该请求被未公开的原因(例如白名单)拒绝。
409 ABORTED 并发冲突,例如读-修改-写冲突。
409 ALREADY_EXISTS 客户端尝试创建的资源已存在。
429 RESOURCE_EXHAUSTED 资源配额达到速率限制。客户端应该查找google.rpc.QuotaFailure错误详细信息以获取更多信息。
499 CANCELLED 客户端取消请求
500 DATA_LOSS 不可恢复的数据丢失或数据损坏。客户端应该向用户报告错误。
500 UNKNOWN 未知的服务器错误。通常是服务器错误。
500 INTERNAL 内部服务错误。通常是服务器错误。
501 NOT_IMPLEMENTED 服务器未实现该API方法。
503 UNAVAILABLE 暂停服务。通常是服务器已经关闭。
504 DEADLINE_EXCEEDED 已超过请求期限。如果重复发生,请考虑降低请求的复杂性。


命名约定

为提供一致的开发体验,所有命名都应:

  • 简单:为简化可使用广泛接受的短语或缩写;

  • 直观:尽量使用直观、熟悉的术语;

  • 一致:使用正确的英语;同一概念使用相同的名称,不同概念使用不同名称;

命名一致性示例:

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

服务名称

如果一个API是由多个服务组成,那么他们的命名应当更容易被发现:一种方法是所有服务名称共享一个公共前缀。

包名称

包名称应当与产品名称和服务名称保持一致,同时必须包含版本信息:

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

方法名称

方法名称应当使用首字母小写驼峰体的名词:

动词 名词 方法名称 请求 响应
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


以上是关于[Design]-API设计指南的主要内容,如果未能解决你的问题,请参考以下文章

Material Design 现在不仅仅是设计指南

[Medium翻译]RESTful API权威设计指南-设计更好的API

[译]API设计的黄金法则(The Golden Rule of API Design)

A guide to color accessibility in product design(产品设计中的色彩易用性指南)

Java 8 API 设计经验浅析

API设计模式|API Design Patterns