restful接口设计规范
写在前面
首先强调的一点是,RESTful不是一种规范,而是一种风格,它是不具有强制性的。
RESTful规范可以参考,但不能完全照搬。
风格这种东西说不准,公说公有理,婆说婆有理。而在开发团队中,最忌讳的就是不统一。所以我们首先确定以下基本原则:
新增、修改、删除、简单查询可以用RESTful
即简单的crud操作接口,按照RESTful规范
复杂的业务操作,数据同步操作,就按业务最适合的风格来写
比如批量操作,我们中间层很多服务业务很难简单抽象为一个名词。不要把时间精力放在纠结这逻辑到底是个什么资源
一、基本概念:
REST是Representational State Transfer的缩写。直译过来是”表现层状态转化”。
其实这个词组前面省略了个主语–“Resource”,加上主语后就是“资源表现层状态转移”。
是不是每个词我都能看懂,但是放在一起不知道什么意思了?
资源(Resource)
网络中的一个实体。 例如,一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。
表现层(Representation)
“资源”是一种信息实体,它可以有多种外在表现形式。
比如一篇文章,可以使用XML、JSON、HTML的形式呈现出来
状态转化(State Transfer)
访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生”状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是”表现层状态转化”。
为了支持资源的REST化,业界提出了RESTful规范
二、RESTful规范
协议
生产环境,使用https协议
测试环境,目前的条件下使用http协议
路径
域名有两种设计
统一放在主域名下,用路径进行分组
1
example.com/api/XXX
放在子域名下
1
api.example.com/XXX
每个业务模块申请一个子域名,就太多了。所以我们使用第二种
我们的规范
url格式
1 | {域名}/api/[page|inner|outer]/{模块名}/{功能名} |
路径的约定:
命名必须全部小写
资源(resource)的命名必须是
名词,并且必须是复数形式如果要使用连字符,建议使用中划线而不是下划线,下划线字符可能会在某些浏览器或屏幕中被部分遮挡或完全隐藏
当然不建议使用连字符
易读
按照restful规范,接口尽量使用名词,禁止使用动词,下面是一些例子。
1 | GET /zoos:列出所有动物园 |
反例:
1 | /getAllCars |
动作
http动词
| 方法 | 描述 | 幂等 |
|---|---|---|
| GET | 用于查询操作,对应于数据库的 select 操作 |
✔︎ |
| PUT | 用于所有的信息更新,对应于数据库的 update 操作 |
✔︎︎ |
| DELETE | 用于更新操作,对应于数据库的 delete 操作 |
✔︎︎ |
| POST | 用于新增操作,对应于数据库的 insert 操作 |
✘ |
| HEAD | 用于返回一个资源对象的“元数据”,例如数据的哈希或上次更新时间。或是用于探测API是否健康 | ✔︎ |
| PATCH | 用于局部信息的更新,对应于数据库的 update 操作 |
✘ |
| OPTIONS | 获取API的支持哪些方法。 | ✔︎ |
不要机械地通过数据库的CRUD来对应这些动词,很多时候,还是要分析一下业务语义。
关注幂等性
其中,PUT 和 PACTH 都是更新业务资源信息,如果资源对象不存在则可以新建一个,但他们两者的区别是,PUT 用于更新一个业务对象的所有完整信息,就像是我们通过表单提交所有的数据,而 PACTH 则对更为API化的数据更新操作,只需要更需要更新的字段
注意:PUT是要保障幂等的,所以不要在PUT中做+1这种更新。
关于PATCH的使用个人持保留意见。可讨论达成一致。
PATCH在RFC规范是是保障幂等性的,但是建议我们的代码设计上做到幂等。
我们的规范
建议只使用常用的动作
GET:查询
POST:除了查询外的所有
版本
考虑到我们的业务中需要支持多版本的情况几乎没有
如果以后需要支持多版本,在路径的最后加上版本v2…
比如
1 | {域名}/api/[page|inner|outer]/{模块名}/{功能名}/v2 |
不带本版的默认是v1
过滤参数
在get请求中,规范常用的查询参数
分页:
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page-current=2&page-size=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
查询条件:
?animal-type=1:指定筛选条件
参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,
GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。
建议使用 /animals?zoo_id=ID格式
返回结果
服务器返回的数据格式,使用JSON
针对不同操作,服务器向用户返回的结果应该符合以下规范。
- GET /collection:返回资源对象的列表(数组)
- GET /collection/resource:返回单个资源对象
- POST /collection:返回新生成的资源对象
- PUT /collection/resource:返回完整的资源对象
- PATCH /collection/resource:返回完整的资源对象
- DELETE /collection/resource:返回删除的资源对象id
分页结果格式:
1 | "data": { |
状态码(Status Codes)
状态码范围
1 | 1xx 信息,请求收到,继续处理。范围保留用于底层HTTP的东西,你很可能永远也用不到。 |
服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。
1 | 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 |
错误处理
如果状态码是5xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。
1
2
3 {
error: "错误原因"
}