RESTful资源定义规范及实践
文章目录
面试了N多的程序员,知道PUT的都寥寥无几,更别说HTTP状态码了,也对接过国内各大厂的API,竟没一家是遵守RESTful的!所以想要真正推行RESTful规范,那是真的困难重重,不光要培训和训练那些写API的程序员,还要跟合作方各种说服和引导。所以一直酝酿着想写个RESTful这个主题,但是由于自己在实践过程中,总是不断冒出新的问题,新的认识,所以一直不忍下手。刚过五一的这个大周末,闲在家没出门,写不了RESTful这个主题,整理一下RESTful资源这块的实践经验我觉得还是够格的。
RESTful接口成熟度模型
- Level 0:只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。
- Level 1:引入了资源的概念。每个资源有对应的标识符和表达。
- Level 2:使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。
- Level 3:使用 HATEOAS。
资源概述
如下是一个RESTful请求:
1
|
curl -X [HTTP Method] --data-urlencode [Request Data] --header [Request Header] --user-agent [User agent] [URL] |
- 资源标识:[HTTP Method] [Schema]://[Host]:[Port]/[URI]
- Schema:协议[http/https]
- Host:服务器主机、IP或域名
- Port:端口
- URI:/[模块名称]/[模块版本]/[接口名]/[唯一标识]
- HTTP Method:请求方法
- 资源操作
- Request Header:请求头
- Request Data:请求数据
- Other:其他
- 资源表达
- Response Header:响应头
- Response Data:响应数据
- Other:其他
资源标识
HTTP Method
1 2 3 4 5 6 7 |
|HTTP Method |描述 | |--- |--- | |GET |获取,查找 | |POST |新增创建 | |PUT |更新 | |PATCH |部分更新 | |DELETE |删除 | |
资源URI
模块名称
1
|
一般为系统名称或者某一个微服务名称 |
模块版本
1 2 3 4 5 6 |
加入系统版本能使提升接口可用性(上下兼容)和降低重构代价。 因为系统版本号放在uri的最前面,可以通过代理路到不同的接口实现,进而使新老版本共存直至平缓过渡后停掉老系统。 一般如下几种情况需要变更版本号: * 接口名称变更导致新老接口路由冲突 例如:v1/orders?user_id=1 --> v2/:user_id/orders * 接口入参或出参变更导致新老接口冲突 |
资源名称
假设模块地址为[module-uri]
资源型
1 2 3 4 5 6 |
GET [module-uri]/orders 获取订单列表 GET [module-uri]/orders/:id 根据id获取单个订单 POST [module-uri]/orders 创建订单 PUT [module-uri]/orders/:id 根据id更新订单 PATCH [module-uri]/orders/:id 根据id部分更新订单 DELETE [module-uri]/orders/:id 根据id删除订单 |
服务型
1
|
GET [module-uri]/services/search 搜索服务 |
系统设置类
1
|
PUT [module-uri]/settings/langueage 设置系统语言 |
复杂关联关系
当有非常复杂的管理关系,对关联关系这种实体的操作就会有多种理解,这是建议根据返回实体确定属于哪个资源,如果是关联关系,则定义为关系名称。
比如:staff->role->permission
- GET/POST/PATCH/DELETE /staffs 获取、新增、修改、删除员工,员工属性可以有roles、permissions
- GET/POST/PATCH/DELETE /roles 获取、新增、修改、删除角色,角色属性可以有permissions、staffs
- GET/POST/PATCH/DELETE /perssions 获取、新增、修改、删除权限,权限属性可以有roles、staffs
- GET/POST/PATCH/DELETE /staff_role_relations或者authorizations
对一个资源的多种操作
当标准动词已经不满足时,比如导入导出操作,有两种处理方式,一种是将定义新的的动词,还有一种是定义新的资源,由于定义动词需要该到框架,所以建议采用定义资源的方式。
假设数据资源为data
- 新增数据:POST /datas
- 修改数据:PATCH /datas/{id}
- 删除数据:DELETE /datas/{id}
- 查询数据:GET /datas/{id}
- 生成数据:POST /data_generations
- 校验数据:GET /data_validations
- 导出数据:GET /data_export
- 导入数据:POST /data_import
资源操作
请求头
- Accept:服务器需要返回什么样的content。如果客户端要求返回”application/xml”,服务器端只能返回”application/json”,那么最好返回status code 406 not acceptable(RFC2616)。
- If-Modified-Since/If-None-Match:如果客户端提供某个条件,那么当这条件满足时,才返回数据,否则返回304 not modified。
- If-Match:在对某个资源做PUT/PATCH/DELETE操作时,服务器应该要求客户端提供If-Match头,只有客户端提供的Etag与服务器对应资源的Etag一致,才进行操作,否则返回412 precondition failed。
请求数据
资源表达
数据格式
采用hal+json规范。
数据类型
由于Number、Boolean和Null在不同编程语言会有不确定性,所以建议只使用String、Array、Object。
错误码
采用problem+json - RFC 7807规范。并将title作为错误码。参考API错误码规范