@lupnfer
2017-03-21T01:43:28.000000Z
字数 6283
阅读 1133
RESTful API Design Principle
Design
在此输入正文
最终希望提供比较符合规范的RESTful的API。
IA10K业务的逻辑最终梳理到以资源的方式来链接。
典型的一个RESTful API 需要支持:GET/POST/PUT/DELETE,IA10K设计实现支持为以下五个方法:GET/POST/PUT/DELETE/HEAD
http(s)://server/comp/[version/]endpoint[?parameters]
字段 | 含义 | 说明 |
---|---|---|
server | IA集群服务器所在的域名或IP地址 | |
comp | 组件,当前为ia10k,支持白牌化,产品定制 | |
version | 格式类似: v1、v2、v23 等等 | 可选 |
endpoint | 资源名称或者服务端点 | 比如 users, tasks, parameters |
对于考虑到部分Proxy服务器已经网关设备仅仅运行通过GET和POST,RESTful服务支持通过HTTP Header进行复写HTTP Method,具体字段为:X-HTTP-Method-Override,可以参考RFC3339。
每次访问API的时候需要带上Access-Token,使用POST方法访问以下URL,以获取Access-Token:
http(s)://server/comp/[version/]login
登录分三种方式:使用用户名+密码,使用API KEY+API SECRET,以及使用网页跳转(暂不介绍)。
前两种方式的登录分两步完成:首次POST不携带任何数据以获取登录Access-Code和登录加密参数(当前为MD5),通过Access-Code一起加密相关登录参数进行第二次登录以获取后续可以使用的Access-Token。
首次登录获取Access-Code举例如下:
POST http://server/ia10k/login
返回:
{
'access_code': 'MTM2ZGY1YjlmMDA4Y2QK',
'encryption': 'md5'
}
第二次POST(用户名+密码方式):
POST http://server/ia10k/login
{
'username': 'zhangpengguo',
'access_code': 'MTM2ZGY1YjlmMDA4Y2QK',
'login_type': 'userauth',
'login_signature': 'SIGNATURE'
}
其中SIGNATURE = MD5(username + access_code + MD5(用户密码) )
第二次POST(API KEY+API SECRET):
POST http://server/ia10k/login
{
'api_key': 'uniview',
'access_code': 'MTM2ZGY1YjlmMDA4Y2QK',
'login_type': 'apiauth',
'login_signature': 'SIGNATURE'
}
其中SIGNATURE = MD5(API KEY+ access_code + MD5(API SECRET) )
第二次登录返回含有信息如下:
{
'access_token': 'ZjYxMWI3NGYzNjM2YjUK'
}
在后续的API调用中,需要将Access-Token添加到HTTP Header中以达到鉴权的目的。HTTP Header头域为
Authorization,在请求消息头中格式类似如下:
Authorization: WiseToken ZjYxMWI3NGYzNjM2YjUK
如果没有携带Token或携带了非法的Token,访问RESTful API的时候服务侧需要返回 HTTP 401 Unauthorised。同时在响应消息的头域里面返回WWW-Authenticate: WiseToken。
RESTful的服务器根据客户端请求中的HTTP Header中的Accept字段来自动返回相应的格式,目前支持:application/json 和 application/xml。如果没有指定或制定值非法,则返回JSON格式。
字段 | 数据类型 | 是否可选 | 备注 |
---|---|---|---|
errcode | Number | 必须 | 错误码,0代表成功 |
errmsg | String | 可选 | 错误描述,根据请求的Accept-Language 返回指定语言错误描述 |
result | Object | 可选 | 结果数据,xml或者json |
debug | String | 可选 | 调试信息,xml或者json |
RESTful的服务器根据客户端请求中的HTTP Header中的Accept-Language字段来自动返回错误信息,用于客户端的友好显示。目前计划支持:简体中文和英语。默认:英语。
GET 对应获取资源操作,以IA引擎管理为例。
返回所有引擎的列表(默认返回前10个,即默认开启分页):
GET /ia10k/engines
如果需要返回指定ID=somexid的引擎,这里使用engine(单数形式):
GET /ia10k/engine/somexid
GET /ia10k/engines?offset=10&limit=5
如上返回第11-15个引擎。
对于分页返回的结果,总数通过HTTP 响应中的Header字段 X-Total-Count 返回。
GET /ia10k/engines?name=*abc*&description=def*
按照name顺序排:
GET /ia10k/engines?sort=+name
按照description逆序排:
GET /ia10k/engines?sort=-description
GET /ia10k/engines?field=name,id,description
对于GET请求,如果正确需要返回200 OK的HTTP Response,返回Body为JSON或XML,如果是JSON,则格式类似如下:
{
"errcode": 123,
"errmsg": "there is something wrong ...",
"result": {}
}
如果是XML则响应的消息体格式类似如下:
<?xml encoding="utf-8"?>
<response>
<errcode>123</errcode>
<errmsg>there is something wrong ...</errmsg>
<result/>
</response>
POST操作对应资源的创建,例如创建一个engine:
POST /ia10k/engine
请求的消息体对应创建引擎的一些参数信息。以JSON为例类似如下:
{
'name': 'IA-Subnode-01',
'description': 'this ia a demo ia node',
'ipaddr': '192.168.100.100',
'login': 'admin',
'password': '123456'
}
对于POST请求,如果资源创建成功,则返回201 Created的HTTP Response,消息体部分和GET类似,但是往往不带有数据(result)。
PUT操作对应资源的创建或更新,例如更新一个engine:
PUT /ia10k/engine/someid
请求的消息体通常仅需要包含需要修改的部分即可:
{
'name': 'IA-Subnode-00'
}
对于PUT请求,如果资源创建成功或更新资源成功,则返回201 Created。
对应资源的删除操作,如:
DELETE /ia10k/engine/someid
如果删除资源成功,则返回204 No Content。
状态码 | 对应方法 | 备注 |
---|---|---|
200 OK | GET | 服务器成功返回数据 |
201 Created | POST/PUT | 修改或创建数据成功 |
202 Accepted | * | 用于异步任务 |
204 No Content | DELETE | 成功删除数据 |
400 Invalid Request | * | 请求数据格式有误 |
401 Unauthorized | * | 表示用户没有权限 |
403 Forbidden | * | 访问是被禁止的 |
404 Not Found | * | 请求资源不存在 |
406 Not Acceptable | GET | 格式不对,通常是请求的Accept域 不被接受 |
500 Internal Server Error | * | 服务器发生其他错误 |
完整的HTTP状态码定义,请参考 RFC2616关于状态码的定义:https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.htmlrfc2616-sec10
鉴于RESTful均为资源类接口,尽管在设计上IA10K尽量以资源的方式来组织API,但是不可避免的会有部分API无法以资源的形式呈现。在以资源为呈现方式的接口来说Thrift的定义采用一定的规则进行定义。
规则举例:对于资源foobar,如果支持完整CRUD的操作,则定义如下的thrift接口及结构定义:
struct foobar {
// some member defines, ba la ba la bu ...
}
// 查询返回的结果
struct QueryResult {
// 返回查询资源的总数
1: required i64 total,
// 返回的每个string为xml或json字符文本, utf-8编码
2: required list<string> data,
}
// 错误类型
exception IaApiError {
1: required i32 error,
// 对应HTTP层面需要返回的Status Code,比如401等
2: required i32 httpStatus,
3: required string message,
4: required string debug,
}
// 创建接口,返回资源ID
string create (
1: required string token,
// 对应资源类型,对应foobar资源,type应使用"foobar"
11: required string type,
// 对应的数据格式,RESTful 处理层透传数据过来,但需要表明数据类型是xml还是json
12: required string dataFormat,
// 对应的数据 由RESTful 处理层透传
13: required string data,
// 当前的语言,如不设置或设置不正确,认为使用英语,此项主要影响IaApiError中返回的错误消息
21: optional string language,
) throws (
1: required IaApiError ex,
);
// 更新接口
void update {
1: required string token,
// 对应资源类型
11: required string type,
// 对应资源ID
12: required string id,
// 对应的数据格式
13: required string dataFormat,
// 对应的数据
14: required string data,
// 当前的语言
21: optional string language,
) throws (
1: required IaApiError ex,
);
// 查询返回的结果
QueryResult query (
1: required string token,
// 对应资源类型
11: required string type,
// 分页参数,偏移量,默认0
12: optional i64 offset,
// 分页参数,返回数据的量,默认20
13: optional i64 count,
// 过滤查询条件
14: optional map<string, string> filters,
// 排序条件
15: optional list<string> sorts,
// 定制显示
16: optional list<string> fields,
// 当前的语言
21: optional string language,
// 当前返回的string格式,xml或json(默认)
22: optional string responseFormat,
) throws (
1: required IaApiError ex,
);
// 获取某个资源的id
string fetch (
1: required string token,
// 对应资源类型
11: required string type,
// 对应资源ID
12: required string id,
// 当前的语言
21: optional string language,
// 当前返回的string格式,xml或json(默认)
22: optional string responseFormat,
) throws (
1: required IaApiError ex,
);
// 删除接口
void remove {
1: required string token,
// 对应资源类型
11: required string type,
// 对应资源ID
12: required string id,
) throws (
1: required IaApiError ex,
);
在API上我们需要设计含有资源所属关系的RESTful的API,比如访问某个智能业务下的处理的图片结果:
GET /ia10k/task/efghj98/results
对于此类API的访问,我们约定在URL Mapping中去完成映射(通过nginx 的配置或者RESTful层代码实现),避免后台程序的过度设计和实现(API的设计中应该避免出现三级以上的资源关系):
/ia10k/task/ID/results?args -> /ia10k/results?args&task=ID
协议调用关系参考下图:

客户端段可以通过Thrift方式或者RESTful API方式来接入服务。Thrift对外提供的API建立在Async HTTP协议之上,此类型的服务器当前可以对外提供JS的库供Web进行访问(同时也支持其他主流编程语言如C#、C++、Java等)。HTTP服务对外提供的时候会通过nginx一层代理,主要目的是做一些URL映射和路由功能。
RESTful Service作为Thrift客户端访问Thrift API Service,RESTful Service的实现方式待定,可以参考平台使用Java的Jetty实现(目前没有Java开发人员),或者使用:Python实现(基于spyne框架,实现简单后续修改灵活、但新员工中缺乏熟手)或基于Boost.Asio 实现(较稳定高效,但是入门门槛也不低,工作量会偏大)