上个月写了一个团队中的 BaaS API 的设计规范,给大家分享下:
目录
1. 引言... 4
1.1. 概要... 4
1.2. 参考资料... 4
1.3. 阅读对象... 4
1.4. 术语解释... 4
2. API 设计规范... 5
2.1. 地址格式... 5
2.2. 输入与输出... 6
2.2.1. 通用输入数据... 6
2.2.2. 主体输入... 6
2.2.3. 通用输出数据... 6
2.2.4. 状态码... 7
2.2.5. 异常处理... 7
2.2.6. 其它... 8
2.3. API操作设计... 8
2.3.1. 资源型操作... 8
2.3.2. 业务型操作... 12
3. API 帮助文档规范... 12
3.1. 帮助文档内容规范... 12
3.2. 文档编写方法... 13
3.3. 帮助文档XML模板... 13
1. 引言
1.1. 概要
BAAS 平台上的所有 API,必须严格遵守本规范。
通过本文档规范 BAAS 平台所有向外提供 API,体现技术的统一性、规范性。并使得所有 API 尽量靠近业界规范的同时,提高API的易用性、可读性、兼容性等,并方便平台的使用者更快地发现、熟悉所有API以供开发。
主要包含两个方面的规范:API 本身的设计规范、API 帮助文档的编写规范。
1.2. 参考资料
《Representational State Transfer (REST)》
1.3. 阅读对象
· 需要把 API 发布到BAAS 平台中的所有开发者。
· 使用 BAAS API 的开发者。
1.4. 术语解释
Ø BAAS:后端即服务。参见:《BaaS服务的定义、发展以及未来》。
Ø REST:一种开放的基于互联网的软件架构模式。参见:《Representational State Transfer (REST)》。
2. API 设计规范
2.1. 地址格式
对于发布的所有 API,地址应该满足以下格式:
· 格式一,直接访问资源型:
/api/v(version)/area/resources/{id}
· 格式二,资源查询型:
/api/v(version)/area/resources/param1Name/param1Value/param2Name/param2Value/?optionalParameters
· 格式三,资源操作型、跨资源业务型:
/api/v(version)/area/resources or controller/action?parameters
示例:
/api/v1.0/acs/users/ 表示访问所有的用户资源。
/api/v1.0/acs/users/1 表示访问 Id 为 1 的用户。
/api/v1.0/acs/users/group/iws-tech/minAge/30 表示访问 iws-tech 组中最小年龄30岁的用户。
/api/v1.0/acs/accounts/UpdateAllUserFlags 表示更新所有用户的某个标识。
其它说明:
Version 表示版本号,只有两级的版本号。
不同的版本号之间,原则上可以不保证 API 的兼容。
某个版本一旦发布,在同一个版本号之内的 api 升级,必须保证兼容原来发布的 API。不能兼容时,需要使用新的 API 地址,同时必须保留旧的 API。
Area 表示某个业务模块,如 ACS、Org、OneDoc、OnePlus 等。
2.2. 输入与输出
2.2.1. 通用输入数据
对于整个BAAS中每一个 API 的调用都需要提交的数据,使用 Http Header 来进行传输。例如:App 授权码、用户标识 等信息。
某个 Area 中大量 API都需要提交的数据,也应该使用 Http Header 来进行提交。
2.2.2. 主体输入
考虑到接口的扩展性,所有API的输入只能接受一般的 JSON 对象作为输入参数,同时也只能输出一个 JSON 对象。
当输入输出的值是单一值、数组时,需要使用一个对象对其进行封装。
所有 JSON 对象的属性名,全部使用首字母小写的驼峰式语法。
2.2.3. 通用输出数据
对于 CDU 以及修改数据为主的操作型API的响应,都必须返回一个统一的数据格式 Result,该结构定义如下:
{ success: boolean, statusCode: int, message: string, data: object }
其中:
success:表示该操作是否成功。
statusCode:该操作如果有多种返回的状态,使用statusCode进行区分。一般情况下,statusCode 返回1或0表示成功或失败。该属性用于给开发者进行程序分支的逻辑判断使用。
message:总是返回一个可用于客户端显示的字符串。该属性用于显示给软件使用者查看。
data是可选属性。即如果没有额外的数据,可以没有data属性,也可以data 返回 null。
2.2.4. 状态码
状态码分为两类,一个是 Http 状态码;一个是 Result 数据结构中的 StatusCode 状态码。HTTP 状态码表示该 HTTP 请求的处理状态。一个请求是否成功是由 HTTP 状态码标明的. 一个 2XX 的状态码表示成功, 而一个 4XX 表示请求失败.
一般情况下,如果能使用 HTTP 状态码表示的状态,应该优先使用 HTTP 状态码。其次,BAAS 内部的各种业务逻辑状态,则应该由 StatusCode 来标明。
1. 对于 HTTP 状态码而言,所有API暂时只使用以下状态码:
· 200:操作成功返回。
· 201:表示创建成功,POST 添加数据成功后必须返回此状态码。
· 400:请求格式不对。
· 401:未授权。(App、User)
· 404:请求的地址未找到。如 users/1 未找到该资源。
· 500:内部程序错误。
其中,201、404这两个状态码,是需要API开发者在每一个API中,根据业务逻辑的执行结果来主动返回的。其它的状态码由框架统一进行返回。
2. StatusCode
StatusCode将统一使用6位编码,代表所有不同的业务逻辑分支。6位编码中的前两位代表不同的Area (模块),由BAAS平台统一规范。后四位由模块开发者自行定义。如:01表示ACS,那么010001可能表示ACS模块中的登录API的用户名错误、010002表示ACS中的登录API的用户密码错误。
2.2.5. 异常处理
请求失败返回 4XX 后,响应的主体依然是 Result 数据格式。其中 message 表示错误的信息。方便进行调试。如:
HttpStatusCode:404
Response Body:{success:false, statusCode:100003, message:'不存在该用户。'}
2.2.6. 其它
时间的格式:API返回 值中的时间,都统一采用UTC格式 时间。
API的返回值中,如果需要包含调试相关信息(如调用时间、调用次数等),由BAAS平台框架统一处理,不单独在各API中处理。
2.3. API操作设计
每个具体的 API地址,都是一个操作。操作分为两种类型:资源型操作、业务型操作。
2.3.1. 资源型操作
资源型操作是满足REST规范化设计的。在设计API 时,应尽量首选这种模式。即:如果 API 能抽象为资源的CRUD操作的,应该尽量先抽象为对资源的操作。
2.3.1.1. 添加
地址:资源列表地址。如 /users/。
使用 POST动作提交实体对应的JSON格式数据。
2.3.1.2. 更新
地址:具体某个资源的地址。如 /users/1,表示id为1的用户。
动作:使用 PUT 动作提交。
数据格式:实体的 JSON格式数据。其中,JSON 数据中不需要列全所有的属性,只需要列出需要更新的属性即可。
如:PUT /users/1 {username:'hqf'}。
对应的响应是:
HttpStatusCode:200
ResponseBody: { success: true, statusCode: 1, message: '更新成功!'}
(另:如果使用 ASP.NET WebApi 框架搭建API,则这里需要提供统一的框架处理此类型的反序列化。)
2.3.1.3. 删除
地址:具体某个资源的地址。如 /users/1。
动作:使用DELETE动作提供请求。
如:DELETE /users/1
对应的响应是:
HttpStatusCode:200
ResponseBody: { success: true, statusCode: 1, message: '删除成功!'}
2.3.1.4. 批量保存
设计建议:尽量不要为每一个资源提供批量保存的操作。只有在对资源的操作的性能要求较高时,才选择性提供。
地址:资源列表地址。如 /users/。
动作:使用 POST 动作提供数据。
数据格式:使用一个 JSON 对象提交数据,该对象中包含一个属性名为 list,属性类型为数组的属性。该数组中的每一个对象都是要更新的实体对象。
对于每一个实体对象:可以为每一个子实体对象添加 persistenceStatus 属性,值为 Deleted、Modified、New 来表示该实体的状态:删除、更新、添加。如果不提供该属性,那么如果实体有 Id 属性,则表示更新,否则表示添加。
例如:
{list:[
{name:'c1', persistenceStatus:'New'},
{id:1, name:'c2', persistenceStatus:'Modified'},
{id:2, persistenceStatus:'Deleted'}
]}
也可省略为:
{list:[
{name:'c1'},//添加
{id:1, name:'c2'},//更新
{id:2, persistenceStatus:'Deleted'}
]}
2.3.1.5. 保存聚合子
设计建议:在需要更新聚合子实体时,如果公布了聚合子资源 API,那么应该首选这个资源来实现保存。否则,才可以在更新聚合父实体时,同时更新它的聚合子实体。
地址与动作:保存聚合子使用聚合父资源相同的地址和动作,见:更新。
数据格式:聚合父对象中有聚合子对应的属性,该属性使用批量更新中定义的数据格式来定义需要更新的聚合子实体集合。见:批量保存。如:
{name:'parent', children:[
{name:'c1', persistenceStatus:'New'},
{id:1, name:'c2', persistenceStatus:'Modified'},
{id:2, persistenceStatus:'Deleted'}
]}
也可省略为:
{name:'parent', children:[
{name:'c1'},
{id:1, name:'c2'},
{id:2, persistenceStatus:'Deleted'}
]}
2.3.1.6. 查询
· 查询所有资源
地址:资源列表地址。如:/users/。
动作:使用 GET 来进行请求。
· 查询指定id的资源
地址:资源地址+Id。如:/users/1。
动作:使用 GET 来进行请求。
· 其它查询
每一个特殊查询,都需要提供相应的特殊查询地址。必须参数以URI Part 的形式给出,可选参数则以查询字符串的形式给出。例如,使用以下格式:
/users/username/hqf/minAge/30/?optionalParam1=1
如果两个 API 使用了相同的参数,则需要在资源后追加一个查询的名称,用以区分。如:
/users/find2/username/hqf/minAge/30/?optionalParam1=1
· OData 查询
设计建议:尽量不要提供OData查询。
如果要提供OData查询API,必须考虑查询的权限的限制,同时不要公布排序接口,否则性能可能会很差。
· 查询资源的合集
有时,查询不是直接针对某个单一的资源,而是联合查询一系列资源的合集,返回值的格式也与单一资源格式不同。这时,需要为这个资源合集声明一个新的资源地址。例如,查询用户与角色的合集,可以使用新的资源地址:/userRoles/。
2.3.2. 业务型操作
业务型操作表示可能跨越多个资源的逻辑操作。服务器端直接提供的服务。
· 一般只使用 POST 动作,偶尔使用 GET 动作。不能使用 PUT、DELETE 动作。
· Action 不要使用简单的、通用的名称。如不要使用与资源操作冲突的 Get、Add、Update、Delete、Save 等名称。而使用具体的逻辑名称,如 transfer、refreshTag 等……
· 推荐放到单独的服务地址(控制器)中。如:POST /{transaction}/{transfer} {from:'a',to:'b',money:10}。
· 如果只是对某个资源单独的操作,那么也可以放在该资源地址下。如:POST /users/refreshLogoutTime。;
3. API 帮助文档规范
BAAS 平台中的 API 帮助文档将采用统一的格式编写,并以 HTML 页面的形式发布。
帮助文档使用以下地址:GET /api/v1.1/ 返回 1.1 版本 API 的帮助文档首页。
3.1. 帮助文档内容规范
向外公布的每个API的帮助说明,必须至少包含以下几项:
· API 简介
· 请求
o 说明请求的方法、地址。
o URI 参数:如果 URI 中某部分是动态的,请使用大括号说明:api/values/{id}。
o URI 查询参数:如果 URI 地址有参数,描述各项参数与说明。每个参数是否可选。
o 请求标头:如果有特殊的请求标头,需要特别逐一说明。
· 响应
o 说明响应的状态码、内容格式。
o 响应标头:如果有特殊的请求标头,需要特别逐一说明。
o 响应正文:特殊字段、重点必须说明含义。尽量说明响应正文的所有字段意义。
· 可选:授权、备注
· 示例请求与响应
参考示例:
3.2. 文档编写方法
API开发者需要为其公布的每一个 API建立一个XML文档用于详细描述上述的帮助内容。该文档建议以与API对应的方法名起名,方便查找。文档的内容由统一的模板确定。
框架组提供统一的转换工具来生成相应的 API 网页。最终会集成在整个 API 网站中。
3.3. 帮助文档XML模板
该模板以附件形式给出。