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错误码规范