简介
REST(REpresentational State Transfer 表现层状态转移),是一种软件架构风格,是一种架构约束条件和原则。它有一系列的规范。满足这些规范的 API 均可称为 RESTful API。
区别:REST 是一种规范,RESTful API 则是满足这种规范的 API 接口。
REST 规范把所有内容都视为资源,也就是说网络上一切皆资源。
REST 架构对资源的操作有 获取(GET)、创建(POST)、修改(PUT)、删除(DELETE)。
HTTP方法 | 行为 | URI | 说明 |
---|---|---|---|
GET | 获取资源 | /users/admin | 获取 admin 用户的详细信息 |
POST | 创建资源 | /users | 创建一个新用户 |
PUT | 更新资源 | /users/admin | 更新 admin 用户 |
DELETE | 删除资源 | /users/admin | 删除 admin 用户 |
核心特点
- 以资源(resource)为中心。所有的东西都抽象成资源,所有的行为都是在资源上的 CRUD 操作。
- 每个资源都有一个唯一的 URI 标识。例如,有一个用户名为 admin 的用户,可以使用 /users/admin 这个 URI 来进行标识。
- 客户端通过 四种 HTTP 方法,对服务器端资源进行操作,实现 “表现层状态转化”。
- 资源是有状态的。使用 JSON/XML 等在 HTTP Body 里表征资源的状态。
- 无状态,指每个 RESTful API 请求都包含了所有 足够完成本次操作 的信息,服务器端无须保持 session。这对服务器的弹性扩容很重要。
RESTful API 设计原则
URI 设计
资源都是使用 URI 进行唯一标识的,通过规范化可以是 API 接口 更加易读、易用。
Google API Design Guide (谷歌API设计指南)中文版
- URI 路径用小写,不要用大写。
- URI 结尾 不应包含 / 。
- URI 中不能出现下划线 _ ,必须用中划线 - 代替。
- 资源名 使用名词,并且用名词复数表示。资源分为 Collection 和 Member 两种。
- ·Collection:一堆资源的集合。例如系统中用户的集合就是 Collection。Collection 的 URI 标识应该是:https://xxx/users
- Member:单个特定资源。例如系统中特定名字的用户,就是 Collection 里的一个Member。 Member 的 URI 标识应该是 :域名/资源名复数/资源名称 ,例如:https://xxx/users/admin 。
- 避免 URI 层级过深。超过两层的资源嵌套就会很乱,应将其他资源转化成 ? 参数。例如:
/schools/qdu/classes/rooma/students/zhang # 不推荐 /students?school=qdu&class=rooma # 推荐
在实际的 API 开发中,可能 有些操作 不能很好的映射为一个 REST 资源。可以参考一下几点:
- 将一个操作 变成 资源的一个属性。
// 在系统中禁用某个用户 URI: /users/zhangsan?active=false
- 将操作 当做是一个资源的 嵌套资源。
// Github 加减星操作 PUT /gists/:id/star # github star action DELETE /gists/:id/star # github unstar action
- 有时也可以打破这类规范。
// 比如登录操作,不属于任何一个资源,URI 可以设计为: /login
REST 资源操作映射为 HTTP 方法
基本上 RESTful API 都是使用 HTTP 协议原生的 GET、POST、PUT、DELETE 来标识对资源的 CRUD 操作的,参考上面的表格。
对资源的操作应该满足安全性、幂等性:
- 安全性:不会改变资源状态,可以理解为只读的。
- 幂等性:执行 1 次 与 执行 N 次,对资源状态改变的效果是等价的。
HTTP方法 | 安全性 | 幂等性 |
---|---|---|
GET | 是 | 是 |
POST | 否 | 否 |
PUT | 否 | 是 |
DELETE | 否 | 是 |
对于批量删除的需求,需要在请求中携带多个需要删除的资源名,但是 HTTP 的 DELETE 方法不能携带多个资源名,可以使用下面三种方式解决,三种方式有各自的使用场景,整个项目中最好使用统一的方式:
- 发起多个 DELETE 请求。
- (推荐)操作路径中携带多个 id,id 之间使用分隔符分隔。例如:DELETE /users?id=1,2,3 。这样既使用了 DELETE 动词,并且不需要发送多次 DELETE 请求。
- 直接使用 POST 方式,在 body 中传入需要删除的资源列表。
返回格式
一个系统的 RESTful API 会向外界开放多个资源的接口,每个接口的返回格式要把持一致。每个接口都会返回成功、失败,这两种消息的格式也要保持一致。不然,客户端代码要适配不同接口的返回格式。
参考链接:待补充
API 命名
API 命名方式:
- 驼峰命名法(serverAddress)
- 蛇形命名法(server_address)
- 脊柱命名法(server-address)
建议使用:脊柱命名法。因为其它两种需要切换输入法,会增加操作的复杂性,也容易出错。
API 域名
API 的域名设置的两种方式:
- https://domain.com/api
这种方式适合 API 将来不会有扩展的情况。比如起初 domain.com 域名下只有一套 API 系统,未来也只有这一套 API 系统。
- https://user.api.domain.com
如果 domain.com 域名下未来会新增另一个系统 API,最好每个系统的 API 拥有专有的 API 域名。比如:storage.api.domain.com、network.api.domain.com。
API 版本管理
随着时间推移、需求变更,当一个 API 满足不了现有的需求,就需要修改 API。对 API 进行修改,不能影响其他调用系统的正常使用,要做到向下兼容,也就是新老版本共存。
但是,实际场景中很可能会出现同一个 API 无法向下兼容的情况。最好的解决办法就是从一开始就引入 API 版本机制。当不能向下兼容是,就引入一个新的版本,老的版本保留原样。这样既可以保证服务的可用性、安全性,同时也能满足新需求。
在 RESTful API 开发中,通常将版本标识放在如下 3 个位置:
- (推荐)URL 中, 比如:/v1/users 。
- HTTP Header 中,比如:Accept: vnd.example-com.foo+json; version=1.0 。
- Form 参数中, 比如:/users?version=v1 。
统一 分页 / 过滤 / 排序 / 搜索 功能
REST 资源的查询接口,通常情况下都需要实现分页、过滤、排序、搜索功能。这些功能是每个 REST 资源都能用到的,所以可以实现一个公共的 API 组件。
- 分页
在列出一个 Collection 下所有的 Member 时,应该提供 分页功能。例如:
/users?offset=0&limit=20 (offset:指定返回记录的开始位置;limit:指定返回记录的数量)
引入分页功能,可以减少 API 响应的延时;同时可以避免返回太多条目,导致服务器 / 客户端响应特别慢,甚至出现 crash 的情况。
- 过滤
如果用户不需要一个资源的全部状态属性,可以在 URI 参数里指定返回那些属性。例如:
/users?fields=email,username,address 。
- 排序
很多时候会根据 创建时间或者其他因素,列出一个 Collention 中前 100 个 Member,可以在 URI 参数中指明 排序参数。例如:
/users?sort=age,desc 。
- 搜索
当一个资源的 Member 太多的时候,可以按 模糊匹配 的搜索方式,来快速找到所需要的 Member,或者查看是否有名字为 xxx 的资源。
练习
使用 net/http 包,实现一个 RESTful API 服务,访问 /hello 接口,返回 “Hello World” 字符串。