RestFul设计规范
1、说明
在整个文档中,会有一些对于标准和实践的推荐和建议。一些实践是非常重要的,必须严格执行,另一些指导准则并不一定处处适用,但是会在特定的场景下带来益处。为了清楚陈述规范和实践的意图,我们会使用如下术语。
2、通用命名约定
见 命名指南 中的”Restful接口”章节,不一致时以本文档为准。
3、基本设计规范
3.1 关注点分离 ★
设计的时候尽量保持简单,一定要分离请求和响应时关注的不同部分,如:URL、Method、HEADER、body、HTTP Status Codes
3.2 使用HTTPS★
- 外部服务一定要使用TLS(就是HTTPS)来访问API,没有必要指出什么时候需要用,什么时候不需要用,只管任何时候都用它;
- 内部服务应该使用TLS,当前阶段不作为强制规范;
- 对所有非TLS的请求返回403 Forbidden,不要用重定向,这会允许一些不良的客户端行为,而又没有任何好处。依赖重定向的客户端会使流量翻倍,而让TLS毫无意义 — 敏感数据已经在第一次请求时发送出来了。
3.3 版本化API ★
REST版本化和多版本间过渡,是RESTful架构设计和运行时的挑战。因此,最好在一开始就考虑版本。
- 一定要在PATH上定义接口版本,如:
- 如果需要A/B Test,一定要在Request Header上定义,详见Requests设计规
- 一定不要提供默认版本,而由客户端显式指定它使用哪一个特定的版本。
3.4 RequestId追溯★
每个API请求一定要包含一个唯一的UUID
UUID存放在HEAD的X-OHM-Request-Id中,用来追溯。 由客户端,服务器和任何后端服务上记录这些值。 当出现问题时,根据这个值可以更容易地找出问题并更迅速地提供解决方案。它提供了一种机制来跟踪,诊断和调试REST请求。
3.5权限分离★
一定要通过url****和端口区分公共、私有、管理api,如:
- 公共(public):https://xxx.xxx.com/upp/v1/ 【可选端口:80,8000-8999】
- 私有(private):https://internal.xxx.xxx.com:9000/v1/ 【可选端口:9000-9899】
- 管理(admin):https://admin.xxx.xxx.com:9900/v1/【可选端口:9900-9999】
3.6 Etags缓存
可以在所有的请求中带上 ETag 头 ,用于识别返回资源的特定版本。用户可以在随后的请求中通过提供If-None-Match头的值来检查内容是否需要更新。
3.7 Ranges分页
可以对所有可能产生大量数据的响应,可以使用Content-Range头来标记分页请求。
3.8过滤、选择、排序
**过滤 Filtering **:
使用唯一的查询参数进行过滤:
curl +X GET https://xxx.xxx.com/v1/cars?color=red 返回红色的cars
curl +X GET https://xxx.xxx.com/v1/cars?seatsTo=2 返回小于两座位的cars集合
选择 Field selection
移动端能够显示其中一些字段,它们其实不需要一个资源的所有字段,给API消费者一个选择字段的能力,这会降低网络流量,提高API可用性。
curl +X GET https://xxx.xxx.com/v1/cars?fields=manufacturer,model,id,color
排序 Sorting :
允许针对多个字段排序
curl +X GET https://xxx.xxx.com/v1/cars?sort=-manufactorer,+model
这是返回根据生产者降序和模型升序排列的car集合
4 请求Requests设计规范
4.1 资源名 ★
-
一定使用名词而不是动词
- curl +X GET https://xxx.xxx.com/v1/users/{userId}
- curl +X GET https://xxx.xxx.com/v1/getUserByID
-
一定使用复数名词
- /users ý/user
- /users/{userId}/apps ý/user/{userId}/app
- 使用资源名称的复数版本除非有关资源是在系统内的单(例如,系统的整体状态可能是/status)。这使得它在你提到的特定资源的方式是一致的。
4.2 请求头★
Host: xxx.xxx.xxx.com
Date: Mon, 22 Aug 2016 11:21:04 GMT
User-Agent: Apache-HttpClient/4.1.2 (java 1.6)
**Content-Type: application/x-www-form-urlencoded; charset=UTF-8 **
//请求体类型,请根据实际请求体内容设置
Accept: application/json
//请求响应体类型,部分API可以根据指定的响应类型来返回对应数据格式,建议手动指定此请求头,如果不设置,部分HTTP客户端会设置默认值/,导致签名错误
X-OHM-App-Version: 1.0.0.2a
//APP版本号,用于请求路由、A/B Test等场景
X-OHM-Stage: RELEASE
//请求API的Stage,如TEST、RELEASE,API提供者可以选择发布到哪个Stage,只有发布到指定Stage后API才可以调用,否则会提示API找不到/Invalid Url/签名失败等错误
X-OHM-ClientKey: 60022326
//请求的AppKey,只有获得API授权后才可以调用
X-OHM-Time: 2016-04-06T12:00:00Z
//请求时间戳
**X-OHM-RequestId(必须): 7AD052CB-EE8B-4DFD-BBAF-EFB340E0A5AF **
//请求唯一标识,UUID,建议15分钟内Request-Id不能重复,与时间戳结合使用起到防重放作用
X-OHM-Signature: FJleSrCYPGCU7dMlLTG+UD3Bc5Elh3TV3CWHtSKh1Ys=
//请求签名,用于验签,防止伪造请求,根据接口的安全等级自定义规则,一般httpmethod、header、body、url的重要信息都要包含
X-OHM-UserId:
** X-OHM-UserToken:**
//用户Id和Token
X-OHM-Request-Mode:Debug
//是否开启Debug模式,不设置默认关闭,一般API调试阶段可以打开此设置,打开会接口会返回更相信的deug信息;生产上不允许打开。
X-{产品代码}-XXX
//自定义请求头,如X-UPP-XXX
4.3 操作
一般CRUD操作不需要定义在url中,但如果需要一些特殊的操作可以用actions作为path
示例:/apps/{appId}/actions/start
4.4 正确使用http method ★
仅使用以下四个方法:POST/GET/PUT/DELETE
4.5 少用路径嵌套★
数据模型可能有父子嵌套关系,路径可能深度嵌套
示例:https://xxx.xxx.com/v1/users/{userId}/apps/{appId}/docker/{dockerId}
宁愿在根路径上限制资源嵌套,使用嵌套来表示作用域的集合
例如:一个docker属于一个应用,一个应用属于一个用户
示例:
[https://xxx.xxx.com/v1/users/{userId](https://xxx.xxx.com/v1/users/%7BuserId)}
[https://xxx.xxx.com/v1/users/{userId}/apps](https://xxx.xxx.com/v1/users/%7BuserId%7D/apps)
[https://xxx.xxx.com/v1/apps/{appId](https://xxx.xxx.com/v1/apps/%7BappId)}
[https://xxx.xxx.com/v1/apps/{appId}/dockers](https://xxx.xxx.com/v1/apps/%7BappId%7D/dockers)
[https://xxx.xxx.com/v1/dockers/{dockerId](https://xxx.xxx.com/v1/dockers/%7BdockerId)}
5 响应Responses设计规范
5.1 返回适当的状态码 ★
rfc7231#section-6中的定义:
- 1xx (Informational): The request was received, continuing process
- 2xx (Successful): The request was successfully received, understood, and accepted
- 3xx (Redirection): Further action needs to be taken in order to complete the request
- 4xx (Client Error): The request contains bad syntax or cannot be fulfilled
- 5xx (Server Error): The server failed to fulfill an apparently valid request
成功的响应一定要从以下返回码中进行选择:
- 200 OK: 请求GET调用成功,对于DELETE方法同步调用完成,或为PUT方法调用,同步更新现有资源
- 201: 请求POST调用成功,同步完成,或为PUT调用同步创建了一个新的资源
- 202: 接受POST、PUT、DELETE请求,将异步处理请求结果
错误的响应一定要从以下返回码中进行选择,特别注意400错误,普通业务异常一定要返回400:
- 400 Bad Request:请求失败,普通业务异常 & 服务器不理解请求语法
- 401 Unauthorized: 请求失败,因为用户没有通过验证
- **403 ** Forbidden: 请求失败,因为用户没有权限访问特定资源
- 404 Not Found:请求失败,未找到该资源
- 408 Request Timeout:请求超时
- 429 Too Many Requests:超频调用,请稍后再试
- 500 Internal Server Error:服务器内部错误,检查网站状态或报告问题
5.2 UTC时间并用ISO8601格式化 ★
接受和返回时一定只用UTC时间,并用ISO8601格式化,如:
"finishedAt": "2016-04-06T12:00:00Z"
5.3 生成结构化的错误信息 ★
在报错时生成一致结构的响应请求,包括:
- code:一个机器可读的错误,
- message:一个人类可读的错误message,
- extraCode: 附加错误码,一般用于返回外部服务原始错误码, (可选)
- extraMessage: 附加错误消息,一般用于返回外部服务原始错误消息,(可选)
- tracestack:一个程序员可读的错误tracestack,(可选)
- url:一个url为客户端提供进一步错误信息和解决方案(可选)
示例:
| |
[](https://docs.xxx.xxx.com/XXX)
|
6 文档和其他(参考)
6.1 提供机器可读的json schema
提供机器可读的JSON schema来描述你的API,可以用prmd来管理JSON schema,用prmd verify来确保它通过验证
6.2 提供人类可读的文档
提供人类可读的文档帮助客户端开发者们理解你的API。
如果你使用了prmd来创建schema,那么你可以简单的通过prmd doc命令来生成Markdown的endpoint级别的文档。
除了endpoint级别的描述,还要提供概要级别的信息,
如:
- 授权,包括获得和使用授权Token。
- API的稳定性和版本,包括如何选择现有的API版本。
- 通用请求和响应头。
- 错误的序列化格式。
- 各种语言的客户端如何使用API的例子。
6.3 提供可执行的示例
提供可执行的例子,这样用户可以直接在终端输入并看到可以用的API请求。最好的情况是,这些例子可以直接复制粘贴,以最小化用户试用API的成本,
如:
$ export TOKEN=... # acquire from dashboard
$ curl -is https://$TOKEN@xxx.xxx.com/v1/users
如果你使用prmd来生成Markdown文档,免费获得了可执行的示例。
6.4 提供mockapi
[图片上传失败...(image-b07de4-1526024018097)]
6.5 描述稳定性
描述你API的稳定性,以及哪些endpoint依赖于其成熟度,比如使用prototype,development或者production的标识。
可参考 Heroku API compatibility policy 了解哪些接口是稳定的,哪些可能有变动。
一旦你的API宣布为 production-ready 和 稳定版,不要在该API版本上做任何不向前兼容的修改。如果你需要做不向前兼容的修改,创建一个新的版本号。
[图片上传失败...(image-c70619-1526024018097)]