restful
{% note warning no-icon %}
RESTful 是一种系统开发设计风格、原则,可视情况调整。以下内容参考RFC5789。
Noun
- 一般资源
通用于一律使用复数名词
例如:/books 或 /books/123。但有部分人认为应该使用单数名词,因为: /book/123 看似比 /books/123 合理。但想想文件系统的目录命名 (例如/Users或/Documents),其实用复数也没问题。复数可以保持API endpoint的一致性,所以一般资源建议用复数。 - 唯一资源:对 client 而言只有一份的资源
通用于单数名词
例如:user 是指目前验证的使用者,使用者永远只能同时登入一个使用者。
Http Method
Method | Idempotent | Safe | CRUD | OO | 生活动词 | 用途 |
---|---|---|---|---|---|---|
GET | Y | Y | Read | get | get | 取得数据 |
list | 列出数据 | |||||
POST | Create | add | create | 建立一个可以完全独立存在的实体 | ||
add | 增加一个必须依赖于某个实体的实体 | |||||
PUT | Y | Update | set | replace | 取代一个关系,已存在时先删除后建立,不存在时直接建立。 | |
add | 附加唯一关系,两个关系实体可以互相独立存在,且已经存在。 | |||||
PATCH | edit | 编辑某个实体 | ||||
DELETE | Delete | remove | remove delete | 删除某个实体 |
- Safe:该操作不会改变服务器端的资源状态 (而且结果可以被cache),属于 Safe 的操作必定属于 Idempotent
- Idempotent (幂等性):该操作不管做1遍或做n遍,都会得到同样的资源状态结果 (但不一定得到同样的回传值,例如第2次DELETE请求可能回传404),因此client端可以放心retry。
GET
- SAFE:每次执行操作时,GET 只有读取 Resource,不会改变到任何的 Resource (资源, 数据)。
- Idempotent:每次执行操作时,GET 只有读取 Resource,不会改变到任何的 Resource (资源, 数据),所以任何资源的任何状态都是一样的。
POST
- 每次执行操作时,POST 都会建立一个 Resource (资源, 数据)。
- 范例:建立使用者
执行第一次时:建立一个 name = "张无忌" 的 user,但其 id = 1执行第二次时:建立一个 name = "张无忌" 的 user,但其 id = 2,发送同样的请求,可每次都是不同的 Resource。
POST /users
Data:
{
"name": "张无忌"
}
- Create:建立一个可以完全独立存在的实体
- 范例:建立使用者
建立使用者前不需要建立任何的东西,就可以建立使用者了,使用者是可以完全独立的存在。
POST /users
Data:
{
"name": "张无忌"
}
- Add:增加一个必须依赖于某个实体的实体
数据结构:1对多的关系 - 范例:Add a public key on behalf of a user 增加一个代表使用者的公钥
增加这个公钥之前,使用者必须存在,公钥必须归属于某个使用者之下公钥跟姓名一样,使用相同计算机的公钥就会相同,但不表示是同一个使用者,故公钥也会有自己的 ID我每次增加公钥时,都将生成不同的公钥 ID。
POST /admin/users/{username}/keys
PUT
- Idempotent:每次执行操作时,PUT 都会取代 Resource,不管操作几次,使用者获取得 Resource 结果都是一样的。
- Replace:不论资源如何,最终的资源状态都是一样的。
Resource 已存在时,或许不理会、或许先删除后建立 (取代)Resource 不存在时,直接建立 - Add:添加唯一关系,建立这个唯一关系前,两个关连实体都必须存在。在没有建立关系前,两个关连实体都可以互相独立存在。
- 数据结构应为:多对多,且两个关连实体的 PK,同时也是关系实体的 PK、FK。
- 范例:增加使用者与角色的关系
增加使用者跟角色的关系前,使用者跟角色都必须存在;增加使用者跟角色的关系前,使用者跟角色可以独立存在使用者 【小明】,跟角色 2,的关系最多只能有一条关系 (使用者【小明】有角色 2 ),最少没有关系 (使用者【小明】没有角色 2 )执行第二次操作时,使用者【小明】跟角色 2 的从属关系仍然存在,也不会跑出第二条使用者【小明】跟角色 2 的从属关系。
PUT user/{account}/roles
Data
{
"role_id": "2"
}
- 范例:Follow a user 关注一个使用者
增加关注关系时,关注者与被关注者 (都是使用者) 都必须存在;增加关注关系时,关注者与被关注者 (都是使用者) 都必须存在关注者使用者【小明】,跟被关注者使用者【小王】,的关系最多只能有一条关系 (【小明】 关注 【小王】),最少没有关系 (【小明】 不关注 【小王】)执行第二次操作时,关注者【小明】跟被关注者【小王】的关注关系仍然存在,也不会跑出第二条关注者【小明】跟被关注者【小王】的关注关系。
PUT /user/following/{username}
PATCH
- Edit:编辑可独立存在、且已经存在的实体,也就是产生新版本的实体,可能会影响其他 Resource。
- 范例:编辑使用者
编辑使用者,使用者已经存在,且我们可能有纪录编辑时间、编辑人、编辑IP,所以每次的编辑都会造成不一样的结果。
第一次编辑使用者,更新时间变为 08:00,编辑人 【张三】,第二次编辑使用者,更新时间变为 09:00,编辑人 【李四】。
PATCH /users/{account}
DELETE
- Idempotent:每次执行操作时,DELETE 都会删除相同的东西。
- 范例:删除使用者
第一次删除使用者【小明】,删除使用者【小明】第二次删除使用者【小明】,还是删除使用者【小明】,只不过使用者【小明】不存在了。
DELETE /users/{account}
HTTP Status Code
HTTP状态码(HTTP Status Code)是用以表示网页服务器HTTP响应状态的3位数字代码。所有状态码的第一个数字代表了响应的五种状态之一。 除非另有说明,状态码是HTTP / 1.1标准(RFC 7231)的一部分。
而关于 RESTful API 的请求状态,通常有以下两种设计方案:
- 方案一:使用 HTTP 状态码来表示请求状态,200 时返回的内容就是数据。
- 方案二:所有接口都返回 200 ,在响应内容里约定 错误码 或 错误信息。
在实际应用中,应据具体情景及需要进行选择与调整。
方案 | 优劣比较 | |
---|---|---|
方案一 | 优点 | 对服务端来说较为简单方便 |
缺点 | 客户端难以根据状态代码处理复杂问题 | |
方案二 | 优点 | 方便对返回数据进行统一处理和细粒度的控制 |
缺点 | 相当于放弃了HTTP状态代码的语义 |
常用HTTP状态代码
Code | Message | 用途 |
---|---|---|
1XX | Informational response | 此类状态代码通常代表的响应都是信息性的,告诉客户端可以进行下一步操作。 |
100 | Continue | 表示服务端已接收到请求头,客户端可以继续发送请求体(如POST请求)。 |
101 | Switching Protocols | 表示服务端支持更优协议,让客户端在服务端更换协议后重新访问。 |
2XX | Successful | 此类状态代码通常代表请求已成功被服务端接收、理解并接受。 |
200 | OK | 表示请求成功。 |
201 | Created | 表示请求已被实现,通常是在成功创建了某个资源。 |
202 | Accepted | 表示请求已被服务端接收,但尚未进行处理。 |
204 | No Content | 表示请求成功,但不会返回任何内容。 |
205 | Reset Content | 表示请求成功,但不会返回任何内容,并且要求客户端重置窗体。 |
3XX | Redirect | 此类状态代码通常代表本次请求需要客户端采取进一步操作才能完成。通常用于复位向。 |
300 | Multiple Choices | 表示请求的资源有多个供可选择,客户端可自行选择一个进行请求的复位向。 |
301 | Moved Permanently | 表示请求的资源已经永久地移动到了新位置,并且将在Location域中携带该资源新的URI。 |
304 | Not Modified | 表示请求的资源无发生修改,将不会返回任何资源。 |
4XX | Client Error | 此类状态代码通常代表客户端可能出现了错误。 |
400 | Bad Request | 表示客户端发出的请求有误(格式、大小、无效的...),服务端不能/不会处理该请求。 |
401 | Unauthorized | 表示客户端未能提供必要的验证,服务端拒绝提供资源。 |
403 | Forbidden | 表示服务端理解了该请求,但客户端没有足够权限以访问,遂拒绝提供该资源。 |
404 | Not Found | 表示服务端无法找到请求的资源,其可能已经暂时(永久)失效。 |
408 | Request Timeout | 表示请求超时。 |
409 | Conflict | 表示请求的资源发送了冲突,通常是PUT请求。 |
410 | Gone | 表示请求的资源已经永久失效,客户端不应再次请求。 |
411 | Length Required | 表示服务端拒绝在没有定义Content-Length头的情况下接收该请求。 |
5XX | Server Error | 此类状态代码通常代表由于服务端的原因,导致无法完成请求。 |
500 | Internal Server Error | 表示由于服务端遇到意料之外的变故,导致无法完成请求。 |
501 | Not Implemented | 表示服务端不支持完成请求所需的功能,导致无法完成请求。 |
502 | Bad Gateway | 表示作为网关或代理的服务段在执行请求时,从上游服务器获得了无效的响应。 |
503 | Service Unavailable | 表示由于某些原因(服务器超载或系统维护等),导致暂时无法完成请求。 |
504 | Gatewy Timeout | 表示作为网关或代理的服务段在执行请求时,未能及时从上游服务器获得响应。 |
505 | HTTP Version Not Supported | 表示服务端不支持请求的HTTP协议版本,导致无法完成请求。 |