不管你部署的是什么服务,只要对外提供 API,那么就绕不开 API 格式的定义。
很多人的 API 可能是这个样子的:
www.baidu.com/api/v1/getUsername?id=1
或者
www.baidu.com/app/index.php?r=info/user/getUsername&id=1
如果你的 API 是这样的,那我们就可以说你的 API 很不 RESTful。
API 风格
首先说明,不管你的 API 属于哪种风格,只要能够满足工作需要,就是一个优秀的设计。API 格式并不存在绝对的标准,只存在不同的设计风格。
API 设计包含两部分:请求和响应。而请求包含:请求 URL、请求方法、请求头部信息等。响应包含:响应体和响应头部信息。
先看一个请求 URL 的组成,它的请求方法为 GET:
https://www.baidu.com:443/app/index.php?r=info/user/getUsername&id=1#tag
# 请求协议
protocal: https
# 请求端口
port: 443
# 请求域名
host: www.baidu.com
# 请求路径
pathname: /app/index.php
# 请求查询字符串
search: r=info/user/getUsername&id=1
# 页面书签
hash: #tag
根据这个 URL 组成,我们介绍几种在删除 id= 1 的作者编写的类别为 2 的所有文章时,常见的 API 风格:
# 纯请求路径
GET www.baidu.com/articles/delete/authors/1/categories/2
# 一级使用路径,二级以后使用查询字符串
GET www.baidu.com/articles/delete/author/1?category=2
# 纯查询字符串
GET www.baidu.com/deleteArticles?author=1&category=2
# RESTful 风格
DELETE www.baidu.com/articles?author=1&category=2
前面三种中,主要的区别在于多个查询条件时怎么传递查询字符串,有的通过使用解析路径,有的通过解析传参,有的两者混用。同时在描述 API 功能时,可以使用 article/delete,也可以使用 deleteArticles。
但它们与第四种 RESTful API 最大的区别在于行为动词 DELETE 的位置不同。
RESTful 设计风格
REST(Representational State Transfer 表现层状态转移)是一种软件架构风格、设计风格,而不是标准,仅提供设计原则。主要用于客户端和服务端的 API 交互,它的优势在于更简洁、清晰、可读性强。
REST 的主要特点是:
- 客户端和服务端是无状态的,任意请求都包含了处理需要的所有信息,同时服务端的变更对客户端是透明的。
- 目标资源用 URI(Universal Resource Identifier 通用资源标识)来表示,通过请求方法来指明操作类型:GET/POST/PUT/DELETE。
无状态是最重要的特性,大部分的 Client-Server,Brower-Server 也都能很好的支持。所以我们主要关注第 2 点即可。
REST URL
表现层状态转移(REST)是一个大的概念,也不好理解,我的理解就是在 URL 的定义上能够清楚的表示其请求含义。它的核心思路就是动词 + 宾语:
DELETE www.baidu.com/api/v1/articles?author=1&category=2
# 动词 DELETE,表示要进行的操作是删除,即状态转移
# 宾语 articles,表示文章这种资源 URI,推荐用复数,即表现层
# 定语 author=1&category=2,表示具体是什么资源
# 版本 api/v1,这个能够帮助我们更好的进行版本的升级,同时不影响原有的请求
我们用 articels 统一的指明资源,用 author=1&category= 2 来在确定具体的资源,用 GET/POST/PUT/DELETE
来指明要进行的增删改查操作。
这种风格相比于/api/deleteArticles
,声明的方法数量只有 1 /4,各个接口之间的风格也更加统一,调用起来更加方便。
这种方法能够保证浏览器常规能访问的到的 GET 请求对资源来说是安全的。比如别人给我们发送了一个链接:/deleteArticle?id=1
,我们绝对不会希望随便点击一下就会跳转到浏览器访问,然后误删了这个资源。
响应状态码
除了请求 URL 有要求,在响应时也有一些要求。我们知道常用的状态码:
- 1xx: 请求相关信息
- 2xx: 操作成功
- 3xx: 重定向
- 4xx: 客户端错误
- 5xx: 服务端错误
所有的状态码 包含 100 多种,涵盖了绝大多数常见的网络场景,而且由于是网络通用的定义规范和解释,因此我们应该尽可能使用精确的状态码。当前有一些不太恰当的做法是即便请求出错,依然使用 200 状态码,转而将错误信息包含在响应体中,或者响应使用纯文本导致无法和正常数据一样标准化解析,如:
httpCode: 200
response: {
status: 1,
msg: '请求无权限'
}
# 或:httpCode: 200
response: '请求无权限'
但我们其实可以用更精确的状态码 403 代表权限不足,所以合适的响应结果应该是:
# 异常时
httpCode: 403,
httpErrorMsg: '请求无权限'
# 或正常时:httpCode: 200,
response: {
status: 0,
msg: '',
data: []}
总结
RESTful 是一种 API 设计风格,并不是一种强制规范和标准,它的优势在于请求和响应都简洁清晰,可读性强。
我们主要关注几点:
- 无状态
- 请求 URL = 动作(GET/POST/PUT/DELETE)+ 资源
- 响应使用精确的状态码和 JSON 格式数据
参考资料
- RESTful API 最佳实践: http://www.ruanyifeng.com/blo…
- RESTful: https://baike.baidu.com/item/…
- 怎样用通俗的语言解释 REST,以及 RESTful?: https://www.zhihu.com/questio…
- Status Code Definitions: https://www.w3.org/Protocols/…