[关闭]
@lupnfer 2017-03-21T01:43:28.000000Z 字数 6283 阅读 1133

RESTful API Design Principle

Design


在此输入正文

IA10K RESTful API Design Principle

目录

RESTful API的设计目标

最终希望提供比较符合规范的RESTful的API。
IA10K业务的逻辑最终梳理到以资源的方式来链接。
典型的一个RESTful API 需要支持:GET/POST/PUT/DELETE,IA10K设计实现支持为以下五个方法:GET/POST/PUT/DELETE/HEAD

接口格式

  1. 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:

  1. http(s)://server/comp/[version/]login

登录分三种方式:使用用户名+密码,使用API KEY+API SECRET,以及使用网页跳转(暂不介绍)。

前两种方式的登录分两步完成:首次POST不携带任何数据以获取登录Access-Code和登录加密参数(当前为MD5),通过Access-Code一起加密相关登录参数进行第二次登录以获取后续可以使用的Access-Token。

首次登录获取Access-Code举例如下:

  1. POST http://server/ia10k/login

返回:

  1. {
  2. 'access_code': 'MTM2ZGY1YjlmMDA4Y2QK',
  3. 'encryption': 'md5'
  4. }

第二次POST(用户名+密码方式):

  1. POST http://server/ia10k/login
  2. {
  3. 'username': 'zhangpengguo',
  4. 'access_code': 'MTM2ZGY1YjlmMDA4Y2QK',
  5. 'login_type': 'userauth',
  6. 'login_signature': 'SIGNATURE'
  7. }

其中SIGNATURE = MD5(username + access_code + MD5(用户密码) )

第二次POST(API KEY+API SECRET):

  1. POST http://server/ia10k/login
  2. {
  3. 'api_key': 'uniview',
  4. 'access_code': 'MTM2ZGY1YjlmMDA4Y2QK',
  5. 'login_type': 'apiauth',
  6. 'login_signature': 'SIGNATURE'
  7. }

其中SIGNATURE = MD5(API KEY+ access_code + MD5(API SECRET) )

第二次登录返回含有信息如下:

  1. {
  2. 'access_token': 'ZjYxMWI3NGYzNjM2YjUK'
  3. }

Access-Token 的使用

在后续的API调用中,需要将Access-Token添加到HTTP Header中以达到鉴权的目的。HTTP Header头域为

Authorization,在请求消息头中格式类似如下:

  1. Authorization: WiseToken ZjYxMWI3NGYzNjM2YjUK

如果没有携带Token或携带了非法的Token,访问RESTful API的时候服务侧需要返回 HTTP 401 Unauthorised。同时在响应消息的头域里面返回WWW-Authenticate: WiseToken

返回数据格式

RESTful的服务器根据客户端请求中的HTTP Header中的Accept字段来自动返回相应的格式,目前支持:application/json 和 application/xml。如果没有指定或制定值非法,则返回JSON格式。

返回数据的公共格式(兼容IMOS平台要求)

字段 数据类型 是否可选 备注
errcode Number 必须 错误码,0代表成功
errmsg String 可选 错误描述,根据请求的Accept-Language 返回指定语言错误描述
result Object 可选 结果数据,xml或者json
debug String 可选 调试信息,xml或者json

关于多语言

RESTful的服务器根据客户端请求中的HTTP Header中的Accept-Language字段来自动返回错误信息,用于客户端的友好显示。目前计划支持:简体中文和英语。默认:英语。

RESTful接口资源的操作

GET

GET 对应获取资源操作,以IA引擎管理为例。
返回所有引擎的列表(默认返回前10个,即默认开启分页):

  1. GET /ia10k/engines

如果需要返回指定ID=somexid的引擎,这里使用engine(单数形式):

  1. GET /ia10k/engine/somexid
支持分页
GET /ia10k/engines?offset=10&limit=5

如上返回第11-15个引擎。
对于分页返回的结果,总数通过HTTP 响应中的Header字段 X-Total-Count 返回。

支持过滤
  1. GET /ia10k/engines?name=*abc*&description=def*
支持排序

按照name顺序排:

  1. GET /ia10k/engines?sort=+name

按照description逆序排:

  1. GET /ia10k/engines?sort=-description
支持定制显示
  1. GET /ia10k/engines?field=name,id,description
响应消息

对于GET请求,如果正确需要返回200 OK的HTTP Response,返回Body为JSON或XML,如果是JSON,则格式类似如下:

  1. {
  2. "errcode": 123,
  3. "errmsg": "there is something wrong ...",
  4. "result": {}
  5. }

如果是XML则响应的消息体格式类似如下:

  1. <?xml encoding="utf-8"?>
  2. <response>
  3. <errcode>123</errcode>
  4. <errmsg>there is something wrong ...</errmsg>
  5. <result/>
  6. </response>

POST

POST操作对应资源的创建,例如创建一个engine:

  1. POST /ia10k/engine

请求的消息体对应创建引擎的一些参数信息。以JSON为例类似如下:

  1. {
  2. 'name': 'IA-Subnode-01',
  3. 'description': 'this ia a demo ia node',
  4. 'ipaddr': '192.168.100.100',
  5. 'login': 'admin',
  6. 'password': '123456'
  7. }
响应消息

对于POST请求,如果资源创建成功,则返回201 Created的HTTP Response,消息体部分和GET类似,但是往往不带有数据(result)。

PUT

PUT操作对应资源的创建或更新,例如更新一个engine:

  1. PUT /ia10k/engine/someid

请求的消息体通常仅需要包含需要修改的部分即可:

  1. {
  2. 'name': 'IA-Subnode-00'
  3. }
响应消息

对于PUT请求,如果资源创建成功或更新资源成功,则返回201 Created。

DELETE

对应资源的删除操作,如:

  1. DELETE /ia10k/engine/someid
响应消息

如果删除资源成功,则返回204 No Content。

可能出现的HTTP 状态码

状态码 对应方法 备注
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

与Thrift接口并存的兼容方案

鉴于RESTful均为资源类接口,尽管在设计上IA10K尽量以资源的方式来组织API,但是不可避免的会有部分API无法以资源的形式呈现。在以资源为呈现方式的接口来说Thrift的定义采用一定的规则进行定义。

Thrift和RESTful的映射关系

规则举例:对于资源foobar,如果支持完整CRUD的操作,则定义如下的thrift接口及结构定义:

  1. struct foobar {
  2. // some member defines, ba la ba la bu ...
  3. }
  4. // 查询返回的结果
  5. struct QueryResult {
  6. // 返回查询资源的总数
  7. 1: required i64 total,
  8. // 返回的每个string为xml或json字符文本, utf-8编码
  9. 2: required list<string> data,
  10. }
  11. // 错误类型
  12. exception IaApiError {
  13. 1: required i32 error,
  14. // 对应HTTP层面需要返回的Status Code,比如401等
  15. 2: required i32 httpStatus,
  16. 3: required string message,
  17. 4: required string debug,
  18. }
  19. // 创建接口,返回资源ID
  20. string create (
  21. 1: required string token,
  22. // 对应资源类型,对应foobar资源,type应使用"foobar"
  23. 11: required string type,
  24. // 对应的数据格式,RESTful 处理层透传数据过来,但需要表明数据类型是xml还是json
  25. 12: required string dataFormat,
  26. // 对应的数据 由RESTful 处理层透传
  27. 13: required string data,
  28. // 当前的语言,如不设置或设置不正确,认为使用英语,此项主要影响IaApiError中返回的错误消息
  29. 21: optional string language,
  30. ) throws (
  31. 1: required IaApiError ex,
  32. );
  33. // 更新接口
  34. void update {
  35. 1: required string token,
  36. // 对应资源类型
  37. 11: required string type,
  38. // 对应资源ID
  39. 12: required string id,
  40. // 对应的数据格式
  41. 13: required string dataFormat,
  42. // 对应的数据
  43. 14: required string data,
  44. // 当前的语言
  45. 21: optional string language,
  46. ) throws (
  47. 1: required IaApiError ex,
  48. );
  49. // 查询返回的结果
  50. QueryResult query (
  51. 1: required string token,
  52. // 对应资源类型
  53. 11: required string type,
  54. // 分页参数,偏移量,默认0
  55. 12: optional i64 offset,
  56. // 分页参数,返回数据的量,默认20
  57. 13: optional i64 count,
  58. // 过滤查询条件
  59. 14: optional map<string, string> filters,
  60. // 排序条件
  61. 15: optional list<string> sorts,
  62. // 定制显示
  63. 16: optional list<string> fields,
  64. // 当前的语言
  65. 21: optional string language,
  66. // 当前返回的string格式,xml或json(默认)
  67. 22: optional string responseFormat,
  68. ) throws (
  69. 1: required IaApiError ex,
  70. );
  71. // 获取某个资源的id
  72. string fetch (
  73. 1: required string token,
  74. // 对应资源类型
  75. 11: required string type,
  76. // 对应资源ID
  77. 12: required string id,
  78. // 当前的语言
  79. 21: optional string language,
  80. // 当前返回的string格式,xml或json(默认)
  81. 22: optional string responseFormat,
  82. ) throws (
  83. 1: required IaApiError ex,
  84. );
  85. // 删除接口
  86. void remove {
  87. 1: required string token,
  88. // 对应资源类型
  89. 11: required string type,
  90. // 对应资源ID
  91. 12: required string id,
  92. ) throws (
  93. 1: required IaApiError ex,
  94. );

关联资源的RESTful API

在API上我们需要设计含有资源所属关系的RESTful的API,比如访问某个智能业务下的处理的图片结果:

  1. GET /ia10k/task/efghj98/results

对于此类API的访问,我们约定在URL Mapping中去完成映射(通过nginx 的配置或者RESTful层代码实现),避免后台程序的过度设计和实现(API的设计中应该避免出现三级以上的资源关系):

  1. /ia10k/task/ID/results?args -> /ia10k/results?args&task=ID

实现方案参考

协议调用关系参考下图:

![API Stack 01](res\API Stack 01.svg)

客户端段可以通过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 实现(较稳定高效,但是入门门槛也不低,工作量会偏大)

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注