理解 REST 设计
REST 的起源
REST 首次提出是 2000 年 Roy Thomas Fielding 发表的博士论文。REST 的全称是表现层状态转移(Representational State Transfer),实际上可以认为是超文本传输“HTT”(Hypertext Transfer)的进一步抽象。
REST 的相关概念
资源(Resource)
资源可以理解为一个应用中的实体,访问一个应用时,我们会与许多资源交互,比如阅读一篇文章时,文章属于一个资源、文章的每一条评论属于一个资源、每一条评论所对应的用户也是一个资源。每一种资源都可以用特定的 URI 指定,比如 /article/233
可以指定 id 为 233 的文章。
表现层(Representation)
也叫做“表征”,对应的是不同资源的不同表现形式,比如用浏览器访问一篇文章,浏览器向服务器发送“我需要这个文章的 HTML 资源”,服务器则返回 HTML 格式的文章,而使用 APP 或者 SPA 应用向服务器交互则可能返回的是 json 格式的文章。服务器返回什么格式的资源往往取决于 HTTP Header 中的 Content-Type 字段,比如Content-Type : application/json; charset=utf-8
,则说明该资源会以 JSON 的格式来返回,请使用 UTF-8 字符集进行处理。
状态转移(State Transfer)
访问一个应用,就是客户端与服务端进行交互的一个过程。而当前访问的上下文信息也就表示着当前的状态。我们平时说 HTTP 是无状态协议是指状态存在服务端,如果想要改变状态,那么客户端就需要进行某些操作,让服务端发生“状态转移”。
资源都对应着一个名词命名 URI,恰好 HTTP 定义好了几种方法(GET、POST、PUT、PATCH、DELETE...)就可以表示对资源状态的变更。
REST API 设计概述
资源
每个 URI 表示一种资源,不能使用动词,比如获取文章不应该使用/articles/1/show
,正确的 URI 应该是 /articles/1
,对于获取这个操作,使用 GET 方法。
动作
对于资源的几种动作要使用 HTTP 的几种方法
方法 | 动作 |
---|
GET | 获取资源 |
POST | 新增资源 |
PUT | 整体更新资源 |
PATCH | 局部更新资源 |
DELETE | 删除资源 |
示例:
GET /articles
:获取所有文章
GET /articles/233/comments
:获取 id 为 233 的文章下面的评论
POST /articles
:新增文章
PUT /articles/233
:整体更新指定文章(提供全部内容)
PATCH /articles/233
:局部更新指定文章(提供部分内容)
DELETE /articles/233
:删除指定文章
信息过滤
如果不想要获取某 URI 下所有资源,可以利用 HTTP 的 query 参数进行过滤信息。
示例:
- ?limit=10:指定返回的记录数量
- ?offset=20:指定记录偏移量
- ?page=2&size=10:指定页数和一页的数量
- ?name=zhangsan:指定某参数,如名称为 zhangsan
参数的设计允许存在冗余,即允许 API 路径和 URL 参数偶尔有重复。比如,GET /articles/233/comments
与 GET /comments?article_id=233
的含义是相同的。
状态码
利用 HTTP 规范的状态码可以表示操作的不同结果。
示例
200 OK
- [GET]:表示成功返回用户请求的数据(GET)201 CREATED
- [POST/PUT/PATCH]:表示新建或更新资源成功(POST、PUT、PATCH)202 Accepted
- [GET]:表示一个请求已进入后台队列(异步任务)204 NO CONTENT
- [DELETE]:用户删除数据成功。400 INVALID REQUEST
- [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。401 Unauthorized
- [*]:表示用户没有权限(令牌、用户名、密码错误)。403 Forbidden
- [*] 表示用户得到授权(与 401 错误相对),但是访问是被禁止的。404 NOT FOUND
- [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。406 Not Acceptable
- [GET]:用户请求的格式不可得(比如用户请求 JSON 格式,但是只有 XML 格式)。410 Gone
-[GET]:用户请求的资源被永久删除,且不会再得到的。422 Unprocesable entity
- [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。500 INTERNAL SERVER ERROR
- [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
异常信息
如果状态码不是成功状态码,就应该返回错误信息,如
HTTP/1.1 400 INVALID REQUEST
{
"message": "参数格式错误"
}
超文本驱动
超文本驱动期望的是可以让客户端无需查阅文档也能知道后续可以进行的操作,也就是接下来可以进行的状态转移,由超文本自身驱动
比如,当一个博客管理员调用了下面的接口后
GET /articles
服务端传回来的响应信息应该包括文章列表和可能的后续操作,如
{
"data": [
{
"id": 1,
"title": "第一篇文章",
"links": [
{
"rel": "查看详情",
"link": "/articles/1",
"method": "get"
},
{
"rel": "删除文章",
"link": "/articles/1",
"method": "delete"
}
]
}
]
}
参考资料
《凤凰架构》:REST 设计风格
理解 RESTful 架构
RESTful API 设计指南
HTTP 响应代码