浅淡RESTful API设计规范

目前主流的通讯协议主要有RPC、http/1.1、http/2等,而http中最主流的无疑就是restful了,由于工作的原因,经常需要和不同的外部服务商进行系统集成,给出的文档都说是基于restful规范设计,遗憾的是,在我看来,几乎没有看到过真正可以称之为restful架构的api设计。今天就来谈谈如何设计一个规范、优雅、可读性高的restful api。

关于restful设计的最佳实践,这里还是推荐阮一峰老师的RESTful API 设计指南,个人觉得是国内范围里讲的最好的了。rest架构,从个人角度理解,核心做了两件事情:

  • 资源定位
  • 资源操作

其实从REST的定义中就能看出来,表述层对应的就是描述资源的位置(资源定位),状态转移就是对资源的状态进行变更操作(增删改查)。
RESTful HTTP动词

下面举个实际的例子:假设我们数据库里有一张User表,我们根据表建好了领域对象模型User,按照restful规范设计的接口应该是这样的:

  • 新增用户,[POST] /users

  • 修改用户,[PUT] /users/id

  • 删除用户,[DELETE] /users/id

  • 查找全部用户,[GET] /users

看到这里可能有同学就要问了,干嘛非得这么设计,还要用什么http动词,delete、put神马的我都没用过,平时都是get、post走天下,也用的好好的呀。新增用户不能用/addUser吗?删除用户不能用/deleteUser吗?感觉也很清楚啊(事实上很多公司的所谓的restful接口文档都是这么定义的)好,现在让我们回到前面,复习一下rest的定义,第一条叫做资源定位,如果还不理解,那让我们再想想URL的定义,叫做统一资源定位符,也就是说url是用来表示资源在互联网上的位置的,所以说在url中应该包含动词,只能包含名词,对资源的操作应该体现在http method上面。

如果这样理解还比较抽象的话,这里不妨再打一个比方,比如在jane的网站有一张小汽车的图片,地址是http://jane.com/img/car.jpg,现在jane想设计一个api接口,实现对这张图片的删除操作,这个api应该怎么设计?根据rest的设计规范,很容易得出是

  • [DELETE] http://jane.com/img/car

非常的清晰明了(这里暂时先不考虑调用方是否有权限删除服务器上的资源)
注意这里为了讲述原理没有加资源的后缀.jpg,引用阮一峰老师的话

严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。

在这个例子里,我们可以通过在http header里指定content-type为image/jpeg来申明这个资源是一张jpg格式的图片
接下来,如果要查询(获取)这张图片呢?自然就是

  • [GET] http://jane.com/img/car

再进一步,我们再改造一下这个api,加上.jpg后缀,这个api就变成了

  • [GET] http://jane.com/img/car.jpg

看到这里大家应该都很熟悉了,这就是我们每天上网要进行无数次操作的api,就是这么设计出来的。

我们继续扩展一下,现在我们要获取的不是静态图片资源了,而是一辆小汽车的相关信息,并且需要对车库里的汽车进行增删改查的维护操作。如果用上面讲的那种一般http的写法,可能会写出类似下面这样的api(只用GET和POST方法)

[POST] http://jane.com/garage/addCar
body:{"brand":"ford","model":"focus","price":"120000"}

[POST] http://jane.com/garage/udpateCar?id=123
body:{"brand":"ford","model":"focus","price":"130000"}

[GET] http://jane.com/garage/queryCarList

[GET] http://jane.com/garage/queryCarSingle?id=123

[GET] http://jane.com/garage/deleteCar?id=123

看出问题来了吗?一个严重的问题是url丢失了资源的位置,更重要的是,你可以叫deleteCar,也可以叫eraseCar,还可以叫removeCar,具体什么含义只有设计这个api的人才能说清楚。而如果用http method,那就肯定是DELETE这个方法,所有看这个api的人都知道你提供的是一个删除这个资源的方法,这就叫做语义化,能用最少的话把一个意思表达清楚,这本身就是一种优雅的设计方式。使用rest设计上述api,结果如下:

[POST] http://jane.com/garage/cars
body:{"brand":"ford","model":"focus","price":"120000"}

[PUT] http://jane.com/garage/cars/123
body:{"brand":"ford","model":"focus","price":"130000"}

[GET] http://jane.com/garage/cars

[GET] http://jane.com/garage/cars/123

[DELETE] http://jane.com/garage/cars/123

这里http://jane.com/garage/cars/123代表了id为123的这辆小汽车在网上的唯一位置,本质上和http://jane.com/img/car所代表的含义是一样的。使用rest能带来的额外的好处,是你可以做很方便的权限控制。因为POST、PUT、DELETE、GET等都是标准的http方法,你可以很轻松的在nginx这样的7层代理或者防火墙上设置策略,禁止某些资源的修改及删除操作,而这显然是自定义的url所达不到的。

除了HTTP METHOD,rest另外一套重要的规范就是HTTP STATUS,这套状态码规范定义了常规的api操作所可能产生的各种可能结果的描述,遵循这套规范,会使得你的api变得更加可读,同时也便于各种网络、基础设施进行交易状态监控。经常会用到的status code整理如下:

200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

事情到了这里似乎一切都很美好,可惜人生不如意十之八九,api设计也不可能一帆风顺。总有一些场景是CRUD所抽象不了的,举个简单的例子,用户登陆,如何去匹配CRUD模型?这里我的建议是,先把你的操作对象或者行为抽象为资源,然后就简单了,无非就是对这个资源的CRUD。
针对用户登陆这个场景,我们可以把用户在远程服务器的会话信息抽象为一个资源,这样的话,登陆其实就是在远程服务器增加了一个会话资源,不难想到,登出就是在远程服务器删除了一个会话资源,所以api可以这样设计

[POST] /login
[DELETE] /logout

如果是发送短信呢?似乎更难。。。这里再次请出阮一峰老师

如果某些动作是HTTP动词表示不了的,你就应该把动作做成一种资源。比如网上汇款,从账户1向账户2汇款500元,正确的写法是把动词transfer改成名词transaction,资源不能是动词,但是可以是一种服务

这样的话你把发送短信理解成一种服务,api可以这样设计

[POST]  /smsService
body:{"mobile":"13813888888","text":"hello world"}

最后建议大家去看一下github的api文档,可以说是restful架构最完整的实现了,看完后一定会对restful规范有着更深入的理解。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RESTful API设计规范是一种用于构建可扩展、灵活且易于理解的API架构风格。以下是一些常见的RESTful API设计规范: 1. 使用合适的HTTP方法:根据操作类型选择合适的HTTP方法,如GET用于获取资源,POST用于创建资源,PUT用于更新资源,DELETE用于删除资源。 2. 使用合适的URI:URI应该被设计成有意义且易于理解的结构。使用名词来表示资源,避免使用动词或操作。 3. 使用合适的HTTP状态码:根据操作的结果返回合适的HTTP状态码。例如,200表示成功,201表示资源创建成功,404表示资源不存在等。 4. 使用版本控制:在URI中包含版本号来管理API的变化,以保持向后兼容性。 5. 使用合适的HTTP头部信息:使用适当的HTTP头部信息来提供额外的元数据,如Content-Type和Accept用于指定请求和响应的数据格式。 6. 使用合适的错误处理机制:对于错误情况,返回合适的错误码和错误信息,并提供清晰的错误处理机制。 7. 使用过滤、分页和排序:对于大量数据的查询,提供过滤、分页和排序的功能,以提高性能和用户体验。 8. 使用合适的安全机制:对于敏感数据或操作,使用适当的身份验证和授权机制,如OAuth2.0。 9. 提供合适的文档和示例:为API提供清晰、详细的文档和示例,以便开发者能够快速理解和使用API。 10. 遵循HATEOAS原则:为API提供超媒体驱动的链接,使客户端能够通过链接发现和导航API的资源。 这些是常见的RESTful API设计规范,根据具体项目需求和团队约定,可能会有所调整和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值