理解RESTful API

近日妹子向我求助RESTful API究竟是个什么东西。缘由是她们公司一个新启动的项目由于RESTful API起了争执。服务端同窗坚持要用RESTful API,而前端同窗则认为服务端用RESTful API就会让前端的调用变得更麻烦。最终争议了一下午仍是不了了之。有趣的是他们组的大部分人都不太了解REST是个什么东西。html

实际上一些抽象的东西是不如一些具体的技术好讲解的,就像你给新人讲面向对象同样,这东西得靠时间,靠悟。我以前作过开放平台API的项目。对于RESTful API还算有些了解。万幸没有丢人,口干舌燥以后总算讲明白一些。但这东西真正理解还得多悟、多思考、多练习。固然,若是你有更好的理解,可在评论区与我留言分享!我会第一时间反馈!前端

1、REST

REST,即Representational State Transfer的缩写,翻译过来就是"表现层状态转化"。不得不认可,我在刚开始看到这个名词的时候是一脸懵逼。好了,如今咱们放弃对这个名词的理解。git

实际上,REST只是一种软件架构风格。注意了,它并非一种具体的技术。而更像是一种约束与规范性的东西,它包含了不少原则与限制。而若是一个架构符合REST的原则,就能够称它为RESTful架构。程序员

1.1 资源

在REST中最重要的一个概念就是资源。在面向对象的世界里,咱们提倡万物皆对象,而在REST的世界里则是万物皆资源。所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它能够是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。github

1.2 表现层

"资源"是一种信息实体,它能够有多种外在表现形式。咱们把"资源"具体呈现出来的形式,叫作它的"表现层"数据库

好比,文本能够用txt格式表现,也能够用HTML格式、XML格式、JSON格式表现,甚至能够采用二进制格式;图片能够用JPG格式表现,也能够用PNG格式表现。json

1.3 状态转化

访问一个网站,就表明了客户端和服务器的一个互动过程。在这个过程当中,势必涉及到数据和状态的变化。后端

当下的互联网通讯协议HTTP协议,是一个无状态协议。这意味着,全部的状态都保存在服务器端。所以,若是客户端想要操做服务器,必须经过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是创建在表现层之上的,因此就是"表现层状态转化"。api

在HTTP协议里面,就可使用HTTP动词来对服务器端资源进行操做,实现“表现层状态转化”。如:GET、POST、PUT、DELETE。它们分别对应四种基本操做:GET用来获取资源,POST用来新建资源(也能够用于更新资源),PUT用来更新资源,DELETE用来删除资源。缓存

以网站中常见的用户CRUD操做为例:

如今,咱们再回过头来理解REST(表现层状态转化)——REST是一种经过表现层来操做改变资源状态的软件架构风格

2、RESTful API

RESTful API 就是REST风格的API。它使用URI来描述资源,使用Html、Json、XML等格式表现,经过HTTP动词来操做资源来实现状态转化,使用HTTP状态码反映处理结果

2.1 URI

URI一般由三部分组成:

  1. 访问资源的命名机制;

  2. 存放资源的主机名;

  3. 资源自身的名称。

例如:https://localhost/post/1 (对应URLhttps://localhost/post/1.html)

咱们能够这样解释它:

  1. 这是一个能够经过https协议访问的资源,

  2. 位于主机 localhost上,

  3. 经过“post/1”能够对该资源进行惟一标识(注意,这个不必定是完整的路径)

注意:以上三点只不过是对实例的解释,以上三点并非URI的必要条件,URI只是一种概念,怎样实现无所谓,只要它惟一标识一个资源就能够了。URI只表明资源的实体,不表明它的形式。严格地说,如上面网址最后的".html"后缀名是没必要要的,由于这个后缀名表示格式,属于"表现层"范畴,而URI应该只表明"资源"的位置。

2.2 HTTP动词

经常使用的HTTP动词有下面这些

  • GET:从服务器取出资源(一项或多项)。——幂等

  • POST:在服务器新建一个资源。——非幂等

  • PUT:在服务器更新资源(客户端提供改变后的完整资源)。——幂等

  • PATCH:在服务器更新资源(客户端提供改变的属性)。——幂等

  • DELETE:从服务器删除资源。——幂等

  • HEAD:获取资源的元数据。

  • OPTIONS:获取信息,关于资源的哪些属性是客户端能够改变的。

2.3 HTTP状态码

HTTP协议自己就给咱们提供了丰富的状态码,以用来反映服务器端处理的结果。而在真正使用中绝大对数人仅仅了解会使用200,404,500之流。这就比如36板斧,你始终是会那三板斧。而RESTful Api规范的HTTP状态码的使用,使HTTP协议的优势发挥到了极致。

例如:

  • 200 OK - [GET]:服务器成功返回用户请求的数据,该操做是幂等的(Idempotent)。
  • 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
  • 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
  • 204 NO CONTENT - [DELETE]:用户删除数据成功。
  • 406 Not Acceptable - [GET]:用户请求的格式不可得(好比用户请求JSON格式,可是只有XML格式)。
  • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再获得的。
  • 422 Unprocesable entity - [POST/PUT/PATCH] 当建立一个对象时,发生一个验证错误。
  • 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将没法判断发出的请求是否成功。

注意:当状态码是4或5开头的时候就应该像用户返回错误信息。通常来讲,返回的信息中将error做为键名,出错信息做为键值便可。

{
    error: "Invalid API key"
}

以下表是经常使用的HTTP状态码和描述

CODE HTTP Operation Body Contents Decription
200 GET,PUT 资源 操做成功
201 POST 资源,元数据 对象建立成功
202 POST,PUT,DELETE,PATCH N/A 请求已被接受
204 DELETE,PUT,PATCH N/A 操做已经执行成功,可是没有返回结果
301 GET link 资源已被移除
303 GET link 重定向
304 GET N/A 资源没有被修改
400 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 参数列表错误(缺乏,格式不匹配)
401 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 未受权
403 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 访问受限,受权过时
404 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 资源,服务未找到
405 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 不容许的HTTP方法
409 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 资源冲突,或资源被锁定
415 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 不支持的数据(媒体)类型
429 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 请求过多被限制
500 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 系统内部错误
501 GET,POST,PUT,DELETE,PATCH 错误提示(消息) 接口未实现

2.4.示例

咱们以Web网站中经常使用的用户增删查改成例。设计普通的API接口完成增删查改大体以下:

//添加用户
http://localhost/createuser
//删除id为1的用户
http://localhost/deleteuser?userid=1
//获取用户列表
http://localhost/getuser
//获取id为1的用户
http://localhost/getuser?userid=1
//更新id为1的用户
http://localhost/updateuser?userid=1

咱们经过调用上面不一样的url传递响应的参数来完成用户的增删查改。

而使用RESTful 风格的api该如何完成呢?

在这个例子中很明显,用户就是咱们的资源,使用uri来描述资源就是

http://localhost/user

表现层能够是Json也能够是xml或者其它。

咱们使用HTTP的动词来操做用户这个资源。

  • 使用GET的方式请求http://localhost/user表明查询用户列表
  • 使用GET的方式请求http://localhost/user/1表明查询id为1的用户
  • 使用POST的方式请求http://localhost/user表明建立一个用户
  • 使用PUT的方式请求http://localhost/user/1表明修改id为1的用户
  • 使用DELETE的方式请求http://localhost/user/1表明删除id为1的用户。

能够看到这种风格看起来要更为优雅与简洁,面向资源,一目了然,具备自解释性,充分的发挥了HTTP协议的优势。

2.5 设计上的难点和误区

2.5.1 URI 包含动词

由于"资源"表示一种实体,因此应该是名词,URI不该该有动词,动词应该放在HTTP协议中。

举例来讲,某个URI是/posts/show/1,其中show是动词,这个URI就设计错了,正确的写法应该是/posts/1,而后用GET方法表示show。

若是某些动做是HTTP动词表示不了的,你就应该把动做作成一种资源。好比网上汇款,从帐户1向帐户2汇款500元,错误的URI是:

POST /accounts/1/transfer/500/to/2

正确的写法是把动词transfer改为名词transaction,资源不能是动词,可是能够是一种服务:

POST /transaction HTTP/1.1
Host: 127.0.0.1
   
from=1&to=2&amount=500.00
2.5.2 URI中加入版本号

另外一个设计误区,就是在URI中加入版本号

http://localhost/app/1.0/foo

http://localhost/app/1.1/foo

http://localhost/app/2.0/foo

由于不一样的版本,能够理解成同一种资源的不一样表现形式,因此应该采用同一个URI。版本号能够在HTTP请求头信息的Accept字段中进行区分(参见Versioning REST Services):

Accept: localhost.foo+json; version=1.0

Accept: localhost.foo+json; version=1.1

Accept: localhostfoo+json; version=2.0
2.5.3 面向资源≠面向单表操做

注意,面向资源不等于面向单表操做。不知道为何不少人会把资源对应到数据库里的单张表。其实他们没有任何关系。资源能够是一个文件,能够是缓存里的数据,也能够是数据库里多张表聚合的结果。好比用户这个资源。一般咱们设计数据库的时候出于性能或范式的考虑用户的信息不会放在一张表里。可是在API设计的时候用户就是一个资源,这个资源的数据有可能来自一张表也有多是多张表,甚至缓存。

2.5.4 复杂与特殊的场景如何设计

跟万物皆对象同样,使用「万物皆资源」的思想设计实际项目中的API时,常常会遇到一个问题就是「这玩意究竟是个什么资源?………………算了,我就直接写吧,无论什么风格了」

  • 好比,登陆(login)和登出(logout)应该怎么REST化?
  • 好比,多条件复合搜索条件太多在GET里写不下怎么办?
  • 好比,批量资源的操做id躲到URL都写不下,难道要写几千个UPDATE或DELETE?

其实在真正理解了REST后,这些都不是什么无解的难题,若是无解,那只能说明你还没真正理解,抽象成资源的能力还不到家:

  • 登陆(login)和登出(logout)其实本质上只是对session资源的建立和删除;

    //登陆——使用HTTP POST请求
    POST /localhost/session
    //登出——使用HTTP DELETE请求
    DELETE /localhost/session
  • 咱们能够把search自己抽象成资源,使用POST建立,若是不需持久化,能够直接在Response中返回结果,若是须要(如翻页、长期缓存等),直接保存搜索结果并303跳转到资源地址就好了;

    //HTTP POST建立资源search
    POST /localhost/search
  • 批量操做id多到连url都写不下的请求,应该建立task,用GET返回task状态甚至执行进度;

    //HTTP POST建立Task 
    POST /localhost/task
    
    //HTTP GET获取TASK执行结果
    GET /localhost/task

2.6 优缺点与适用场景

任何一门技术或者思想都有其优缺点,虽然其诞生的初衷都是为了解决咱们的问题,而不是带来更大的灾难。REST一样如此。它的优势很明显,优雅、规范,行为和资源分离,更容易理解。

可是也有其缺点,它面向资源,这种设计思路是反程序员直觉的,由于在本地业务代码中仍然是一个个的函数,是动做,但表如今接口形式上则彻底是资源的形式,对于后端开发人员要求高,有些业务逻辑难以被抽象为资源的增删改查。甚至有些时候RESTful实际上是个效率很低的东西,为了实现一个资源,你须要定义它的一套方式,若是要联合查询又会要求对其衍生或定义一个新的资源。它提供的接口通常是“粗”粒度的,它一般返回的都是完整的数据模型,难以查询符合特殊要求的数据,有些特殊的业务要比普通的API须要更屡次HTTP请求。

REST面对的疑问跟当年刚开始流行面向对象时的状况是同样的。它适合不少状况,但并不适合全部状况。它更适合与一些开放平台API,如新浪微博、GitHub、京东、淘宝开放平台等,开放API之因此开放,就是由于它不知道你到底须要什么返回结果,既然不知道,那么我干脆都返回给你,有客户端自由组合成本身想要的数据。而对于内部开发,有其局限性,内部开发因为需求很是明确,有些时候出于性能或灵活性的考虑,服务端简单粗暴的丢出来完整的数据模型由客户端本身处理显然是不合适的。

对于一些内部的开发,适合用RESTful API的咱们仍然能够用,对于一些不合适的,咱们仍然能够借鉴一些RESTFul中的优势,来设计咱们的API。好比简洁的URI(每一个人看到一坨超长的API地址,心里都是拒绝的),充分利用HTTP状态码等。

最后

RESTful API是REST风格的API,它是一种API设计风格,规范了API设计中的一些原则。它让咱们的API更加优雅、规范。但也尤为缺点,在实际使用过程当中咱们应该充分的取理解它,综合考量其使用场景。

若是你们想要取学习并使用它,建议能够参考Github开放API 或者Elasticsearch API,看一看他们是如何设计的API,对于本身项目中的每个场景多思考,去网上一些开源RESTful API找一找有没有相同场景的例子。

不少人会盲目追新,又对REST的概念和理念只知其一;不知其二,最后搞出一个半吊子的怪胎,不只没有设计出优雅规范的API,甚至还引发了更大的麻烦,最后还自我标榜用了流行的RESTful API。

其实REST规范最终仍是为了开发者和软件产品服务的,若是它能带来便利、减小混乱,就值得用;反之,若是带来的麻烦比解决的还多,跟风追流行就不可取了。其它任何技术也是如此!

相关文章
相关标签/搜索