浅谈 RESTful API
什么是 RESTful
RESTful API 设计参考文献列表
What Is REST?
RESTful 是一种软件设计风格,由 Roy Thomas Fielding 在他 2000 年的论文中提出,Fielding 将他对互联网软件的架构原则,定名为 REST,即 Representational State Transfer 的缩写,译为表现层状态转化,也可理解为用 URL 定位资源,用 HTTP 方法描述操作。
REST 的核心是可编辑的资源及其集合,用符合 Atom 文档标准的 Feed 和 Entry 表示。每个资源或者集合有一个惟一的 URI。系统以资源为中心,构建并提供一系列的 Web 服务。REST 的基本概念和原则包括:系统上的所有事物都被抽象为资源;每个资源对应唯一的资源标识;对资源的操作不会改变资源标识本身;所有的操作都是无状态的;等等。
为何要用 RESTful
按照 RESTful 架构可以充分的利用 HTTP 协议带给我们的各种功能,算是对 HTTP 协议使用的最佳实践,还有一点就是可以使软件架构设计更加清晰,可维护性更好
如何做 RESTful
RESTful 架构
如果一个架构符合 REST 原则,就称它为 RESTful 架构
从以下三个方面理解 RESTful 架构:
资源 -
Resources:所谓资源,就是网络上的一个实体,或者说是网络上的一个具体信息表现层 -
Representation:资源是一种信息实体,它可以有多种外在表现形式。我们把『资源』具体呈现出来的形式,叫做它的『表现层』状态转化 -
State Transfer:互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生『状态转化 -State Transfer』。而这种转化是建立在表现层之上的,所以就是『表现层状态转化』
也主就是说,遵循 REST 原则,设计出来的一个架构就称为 RESTful 架构,比如:GitHub API 就是一个典型的 RESTful 架构
RESTful API 设计
使用 URL 定位资源
GitHub REST API v3
很大程度上,定义的 API 地址要对程序员友好,并且能在浏览器地址栏容易输入。是的,这两个指标也能检验出那些合格的 API 设计者,我就是这样认为的
应该将
API部署在专用域名之下,比如:api.example.com不用大写
用中杠
-而不是_参数列表要
encodeURI中尽量使用名词而不是动词URI中的名词表示资源集合,使用复数形式虽然
/在URI中表达层级,但是避免为了追求REST导致层级过深,适当使用参数表示,比如:GET /animals?zoo=1&area=3&page=1
版本控制
将版本号直接加入
URL中
https://api.example.com/v1https://api.example.com/v2
使用 HTTP 请求头的 Accept 字段进行区分
在这种方式中,客户端在 Accept Header 中存放 Accept: application/vnd.example.v1+json,服务器自定义 Header 返回当前版本信息 X-Example-Media-Type: example.v3; format=json
https://api.example.com/Accept: application/vnd.example.v1+jsonAccept: application/vnd.example.v2+json
请求 GitHub 查看头中自定义的 X-GitHub-Media-Type
$ curl -i https://api.github.com/users/octocat/orgsHTTP/1.1 200 OKDate: Sun, 22 Apr 2018 03:43:57 GMTContent-Type: application/json; charset=utf-8Content-Length: 5Server: GitHub.comStatus: 200 OKX-RateLimit-Limit: 60 # 最大访问次数X-RateLimit-Remaining: 50 # 剩余的访问次数X-RateLimit-Reset: 1524369179 # 到该时间点,访问次数会重置为 X-RateLimit-LimitCache-Control: public, max-age=60, s-maxage=60Vary: AcceptETag: "98f0c1b396a4e5d54f4d5fe561d54b44"X-GitHub-Media-Type: github.v3; format=json # GitHub 服务端自定义 Header 返回当前版本信息Access-Control-Expose-Headers: ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-IntervalAccess-Control-Allow-Origin: *Strict-Transport-Security: max-age=31536000; includeSubdomains; preloadX-Frame-Options: denyX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockReferrer-Policy: origin-when-cross-origin, strict-origin-when-cross-originContent-Security-Policy: default-src 'none'X-Runtime-rack: 0.010912Vary: Accept-EncodingX-GitHub-Request-Id: E5BC:17C8:C2B264:1064F09:5ADC04FD[]
请求 GitHub 接口超过限制次数后的响应
// 当请求到第 61 次时的响应结果$ for (( i=0; i<61; i=i+1 )); do curl -i https://api.github.com/users/octocat/orgs; doneHTTP/1.1 403 Forbidden # 服务器拒绝了Date: Sun, 22 Apr 2018 04:04:15 GMTContent-Type: application/json; charset=utf-8Content-Length: 258Server: GitHub.comStatus: 403 Forbidden # 返回的状态码X-RateLimit-Limit: 60X-RateLimit-Remaining: 0 # 剩余次数为 0 了X-RateLimit-Reset: 1524372880X-GitHub-Media-Type: github.v3; format=jsonAccess-Control-Expose-Headers: ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-IntervalAccess-Control-Allow-Origin: *Strict-Transport-Security: max-age=31536000; includeSubdomains; preloadX-Frame-Options: denyX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockReferrer-Policy: origin-when-cross-origin, strict-origin-when-cross-originContent-Security-Policy: default-src 'none'X-Runtime-rack: 0.012239X-GitHub-Request-Id: E756:2E0E:75FBFF:A0DA73:5ADC09BF{"message": "API rate limit exceeded for 221.223.47.129. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)","documentation_url": "https://developer.github.com/v3/#rate-limiting"}
自定义 Header 头
X-Api-Version: 1使用 HTTP 方法
安全性:不会改变资源状态,可以理解为只读的
幂等性:执行
1次和执行N次,对资源状态改变的效果是等价的,也就是说无论你执行多少次重复的操作都不会给资源造成变更

使用 HTTP 响应代码
请求成功

重定向

条件请求

客户端错误

服务端错误

响应数据格式
为什么都反对 XML 而支持使用 JSON?
当然轮子哥是这样说的『在我长时间使用
XML和JSON的过程中我发现,其实他们是不可互相替代的。我们只能说如今大部分适合XML的程序要么都写完了要么都不时髦了,现在需要JSON的还没写的程序多一点』
GitHub 是在请求的 body 体中使用 JSON 格式来返回数据的
$ curl -i https://api.github.com -u foo:bar...{"message": "Bad credentials","documentation_url": "https://developer.github.com/v3"}
编写文档
一个好的文档也反应出接口开发者的素养(当然那些赶项目进度的除外,笔者确实也经历过这种场景,项目急吼吼的上,就感觉明天做不出来,后天公司就要倒闭的这种,不要说写文档,就自己写的代码 Review 一下都是浪费时间。如果条件允许,我个人还是愿意把程序和文档都写好的)。当然,通过这些,你也看到了我的素养确实也不高,找了一个赶进度的借口不写文档,你愿意这么理解我也就不说什么了
文档的一些原则
每一个接口的请求参数,每个参数的类型限制,是否必填,可选的值等都进行明确
响应结果集中的每个参数都有明确的解释
对于特定场景和专门适配的接口,提供详细的说明,怎么的场景下调用之类等等
显然,这么宏大的标题可不是写一篇文章就能搞定的,以上这些就是我对 RESTful API 的一些理解和总结,后期会补充和完善
