RESTful API 学习笔记详细成长记录 — 深入理解 RESTful
1.概述
REST 是“REpresentational State Transfer”的缩写,可以翻译成“表现状态转换”
但是在绝大多数场合中我们只说 REST 或者 RESTful。Fielding 在论文中将 REST 定位为“分布式超媒体应用(Distributed Hypermedia System)”的架构风格,它在文中提到一个名为“HATEOAS(Hypermedia as the engine of application state)”的概念。
如何正确地使用 Web标准,例如,HTTP 和 URI。如果设计的应用程序能符合 REST 原则 (REST principles),这些符合 REST 原则的 REST 服务可称为 "RESTful web 。
面向最终用户的 Web 应用来对这个概念进行简单阐述:这里所谓的应用状态(Application State)表示 Web 应用的客户端的状态,也可以说是会话状态
。资源在浏览器中以超媒体的形式呈现,通过点击超媒体中的链接可以获取其它相关的资源或者对当前资源进行相应的处理,获取的资源或者针对资源处理的响应同样以超媒体的形式再次呈现在浏览器上。
借助于超媒体这种特殊的资源(网络上的某一个实体,文本、图片、视频、音频或者一种特定服务等)是REST中的核心概念。使用URI表示每个资源。)呈现方式,应用状态的转换体现为浏览器中呈现资源的转换(访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。
)。如果将超媒体进一步抽象成一般意义上的资源呈现(Representation )方式,那么应用状态变成了可被呈现的状态(REpresentational State)。应用状态之间的转换就成了可被呈现的状态装换(REpresentational State Transfer),这就是 REST。
2.版本号
在 RESTful API 中,API 接口应该尽量兼容之前的版本。但是,在实际业务开发场景中,可能随着业务需求的不断迭代,现有的 API 接口无法支持旧版本的适配,此时如果强制升级服务端的 API 接口将导致客户端旧有功能出现故障。实际上,Web 端是部署在服务器,因此它可以很容易为了适配服务端的新的 API 接口进行版本升级。为了解决这个版本不兼容问题,在设计 RESTful API 的一种实用的做法是使用版本号。一般情况下,在 url 中保留版本号,并同时兼容多个版本。
【GET】 /v1/users/{user_id} // 版本 v1 的查询用户列表的 API 接口
【GET】 /v2/users/{user_id} // 版本 v2 的查询用户列表的 API 接口
3.资源路径
RESTful API 的设计以资源为核心,每一个 URI 代表一种资源。因此,URI 不能包含动词,只能是名词。注意的是,尽量少用形容词。不论资源是单个还是多个,API 的名词以复数进行命名。此外,命名名词的时候,要使用小写、数字及下划线来区分多个单词。这样的设计是为了与 json 对象及属性的命名方案保持一致。例如,一个查询系统用户的接口可以进行如下设计。
【GET】 /v1/users/{user_id}
同资源的路径应该从根到子依次如下
/{resources}/{resource_id}/{sub_resources}/{sub_resource_id}/{sub_resource_property}
“添加用户的角色”的设计,其中“用户”是主资源,“角色”是子资源。
【POST】 /v1/users/{user_id}/roles/{role_id} // 添加用户的角色
资源变化难以使用标准的 RESTful API 来命名,可以用特殊的 actions 命名。
/{resources}/{resource_id}/actions/{action}
“密码修改”这个接口的命名很难完全使用名词来构建路径,此时可以引入 action 命名。
【PUT】 /v1/users/{user_id}/password/actions/modify // 密码修改
4.HTTP动词请求
客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:-
- GET用来获取资源
- POST用来新建资源(也可以用于更新资源)
- PUT用来更新全部资源,
- DELETE用来删除资源。
还有一个 PATCH
用于更新服务端的资源的部分信息
还有两个不常用的HTTP动词。
- HEAD:获取资源的元数据。
- OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
【GET】 /students # 查询学生信息列表
【GET】 /students/1001 # 查看某个学生信息
【POST】 /students # 新建学生信息
【PUT】 /students/1001 # 更新用户信息(全部字段)
【PATCH】 /students/1001 # 更新用户信息(部分字段)
【DELETE】 /students/1001 # 删除用户信息
5.查询参数—过滤信息(Filtering)
如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。其中,offset 指定返回记录的开始位置。一般情况下,它会结合 limit 来做分页的查询,这里 limit 指定返回记录的数量。
下面是一些常见的参数。
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件
结合起来:
【GET】 /{version}/{resources}/{resource_id}?offset=0&limit=20
orderby
可以用来排序,但仅支持单个字符的排序,如果存在多个字段排序,需要业务中扩展其他参数进行支持。
count
表示返回数据是否包含总条数,它的默认值为 false。
6.状态码(Status Codes)
服务器向用户返回的状态码和提示信息,常见的有以下一些
个人从表中看出(可能不全面):
- 200左右的是成功的,其中偶数是幂等的
- 400左右的是请求不成功的,其中偶数是幂等的
- 500左右的是服务器错误,用户将无法判断发出的请求是否成功。
状态码 | HTTP动词 | 描述 |
---|---|---|
200 | [GET] | 请求成功服务器成功返回用户请求的数据,该操作是幂等的(Idempotent) |
201 | [POST/PUT/PATCH] | 用户新建或修改数据成功。 |
400 | [POST/PUT/PATCH] | 用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 |
401 | [*] | 表示用户没有权限(令牌、用户名、密码错误)。未验证 |
403 | [*] | 表示用户得到授权(与401错误相对),但是访问是被禁止的。 |
404 | [*] | 用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 |
409 | [*] | 资源冲突 |
500 | [*] | 服务器发生错误,用户将无法判断发出的请求是否成功。 |
错误处理(Error handling)
当 RESTful API 接口出现非 2xx 的 HTTP 错误码响应时,采用全局的异常结构响应信息。
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"code": "INVALID_ARGUMENT",
"message": "{error message}",
"cause": "{cause message}",
"request_id": "01234567-89ab-cdef-0123-456789abcdef",
"host_id": "{server identity}",
"server_time": ""
}
如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。
{ error: "Invalid API key" }
返回结果
针对不同操作,服务器向用户返回的结果应该符合以下规范。
- GET /collections:返回资源对象的列表(数组)
- GET /collections/resources:返回单个资源对象
- POST /collections:返回新生成的资源对象
- PUT /collections/resources:返回完整的资源对象
- PATCH /collections/resources:返回完整的资源对象
- DELETE /collections/resources:返回一个空文档
如果是单条数据,则返回一个对象的 JSON 字符串。
如果是列表数据,则返回一个封装的结构体。