RESTful服务至上实践

本文主要读者

引言

REST是什么

  统一接口

    据悉资源

    通过特征来操作资源

    自描述的音讯

    超媒体即选拔状态引擎(HATEOAS)

  无状态

  可缓存

  C-S架构

  分层系统

  按需编码(可选)

REST神速提醒

  行使HTTP动词表示一些意思

  理所当然的资源名

  XML和JSON

  创建适当粒度的资源

  设想连通性

定义

  幂等性

  安全

HTTP动词

  GET

  PUT

  POST

  PUT和POST的始建相比

  DELETE

资源命名

  资源URI示例

  资源命名的反例

  复数

回来表征

  资源通过链接的可发现性(HATEOAS续)

    小小的化链接推荐

    链接格式

  卷入响应

  处理跨域难点

    支持CORS

    支持JSONP

查询,过滤和分页

  结果限制

    用范围标记进行界定

    用字符串查询参数进行限定

    据悉范围的响应

  分页

  结果的过滤和排序

    过滤

    排序

劳务版本管理

  因而情节协商辅助版本管理

  当没有点名版本时,再次来到什么版本?

  请求不扶助的版本

  怎么着时候应该制造一个新本子?

    破坏性的修改

    非破坏性的改动

  版本控制应在怎么样级别出现?

  使用Content-Location来增强响应

  带有Content-Type的链接

  找出接济的版本

    本人应该而且扶助几个本子?

    弃用

    自家怎么告知客户端被弃用的资源?

日子/时间处理

  Body内容中的日期/时间体系化

  HTTP
Headers中的日期/时间序列化

有限支持服务的平安

  身份验证

  传输安全

  授权

  应用程序安全

缓存和可伸缩性

  ETag Header

HTTP状态码(前10)

外加资源

  书籍

  网站

 

本文主要读者

  该最佳实践文档适用于对RESTful
Web服务感兴趣的开发人士,该服务为跨七个劳务的零部件提供了较高的可相信性和一致性。按照本文的点拨,可连忙、广泛、公开地为内外部客户使用。

  本文中的指引原则一致适用于工程师们,他们愿意选用那么些依据最佳实践标准开发的服务。就算她们越发爱惜缓存、代理规则、监听及安全等连锁方面,然而该文档能作为一份包涵所有项目服务的总指南。

  别的,通过从这个率领标准,管理人士明白到开创公共的、提供高稳定性的服务所需成本的努力,他们也可从中收益。

 

引言

  现今已有大气有关RESTful
Web服务至上实践的连带资料(详见本文最终的连锁文献部分)。由于撰文的时光不一致,许多资料中的内容是争辨的。其它,想要通过查看文献来打探那种劳动的升华是不太可取的。为了精通RESTful这一概念,至少需求查阅三到五本有关文献,而本文将可以帮您加快这一进度——扬弃多余的议论,最大化地提炼出REST的特等实践和正式。

  与其说REST是一套标准,REST更像是一种口径的聚众。除了三个根本的尺码外就从未其余的正规化了。实际上,就算有所谓的“最佳实践”和业内,但这个东西都和宗派斗争一样,在不断地演化。

  本文围绕REST的常见难点提出了见识和仿食谱式的议论,并经过介绍一些粗略的背景知识对成立真实意况下的预生产条件中相同的REST服务提供文化。本文收集了来自其他渠道的音讯,经历过一次次的败诉后不断创新。

  但对此REST格局是或不是肯定比SOAP好用仍有较大争议(反之亦然),也许在少数情状下仍亟需创造SOAP服务。本文在提及SOAP时并未花较大篇幅来啄磨它的争执优点。相反由于技术和行业在不断升高,我们将继续持之以恒大家的倘诺–REST是即时规划web服务的顶级艺术。

  第一有的概述REST的意义、设计准则和它的特有之处。第二片段罗列了一些小贴士来回想REST的劳务意见。之后的有的则会更深切地为web服务创造人员提供部分细节的协助和钻探,来贯彻一个可见精晓显示在生养条件中的高质量REST服务。

 

REST是什么?

  REST架构格局讲述了五种设计准则。这一个用于架构的设计准则,最早是由罗伊菲尔德ing在她的大学生杂谈中提出并定义了RESTful风格。(详见http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm

  四个规划准则分别是:

  • 统一接口
  • 无状态
  • 可缓冲
  • C-S架构
  • 分段系统
  • 按需编码

  以下是这一个规划准则的详实座谈:

联合接口

  统一接口准则定义了客户端和服务端之间的接口,简化和分手了框架结构,那样一来每个部分都可单独演变。以下是接口统一的多个规范:

  基于资源

  不一样资源须求用URI来唯一标识。再次来到给客户端的特点和资源本身在概念上有所分裂,例如服务端不会直接传送一个数据库资源,不过,一些HTML、XML或JSON数据可知展现部分数据库记录,如用藏语来发挥仍然用UTF-8编码则要基于请求和服务器已毕的底细来支配。

  通过特色来操作资源

  当客户端收到包罗元数据的资源的性状时,在有权力的情况下,客户端已控制的够用的新闻,可以对服务端的资源举行删改。

  自描述的新闻

  每条音信都带有丰盛的数目用于确认音信该怎么处理。例如要由互连网媒体类型(已知的如MIME类型)来认同需调用哪个解析器。响应同样也标志了它们的缓存能力。

  超媒体即利用状态引擎(HATEOAS)

  客户端通过body内容、查询串参数、请求头和URI(资源名称)来传送状态。服务端通过body内容,响应码和响应头传送状态给客户端。那项技术被叫做超媒体(或超文本链接)。

  除了上述内容外,HATEOS也代表,必要的时候链接也可被含有在重临的body(或底部)中,以提供URI来寻找对象自我或关系对象。下文将对此举办更详细的阐释。

  统一接口是各种REST服务规划时的必备准则。

无状态

  正如REST是REpresentational State
Transfer的缩写,无状态很要紧。本质上,那声明了处理请求所需的状态已经包涵在乞请我里,也有可能是URI的一片段、查询串参数、body或尾部。URI可以唯一标识每个资源,body中也隐含了资源的转态(或转态变更情状)。之后,服务器将展开拍卖,将有关的气象或资源通过尾部、状态和响应body传递给客户端。

  从事大家这一行业的半数以上人都习惯使用容器来编程,容器中有一个“会话”的定义,用于在七个HTTP请求下保持状态。在REST中,假诺要在多个请求下保持用户景况,客户端必须概括客户端的保有音信来成功请求,须要时再也发送请求。自从服务端不须求保证、更新或传递会话状态后,无状态性得到了更大的延展。其它,负载均衡器无需担心和无状态系统里面的对话。

  所以状态和资源间有啥样分化?服务器对于状态,或者说是应用状态,所关注的点是在当下对话或请求中要形成请求所需的多寡。而资源,或者说是资源气象,则是概念了资源特点的数量,例如存储在数据库中的数据。一句话来说,应用状态是是随着客户端和请求的改变而更改的数码。相反,资源情形对于发出请求的客户端的话是不变的。

  在网络利用的某一特定岗位上摆放一个重返按钮,是因为它希望你能按自然的相继来操作吗?其实是因为它违反了无状态的尺度。有为数不少不遵守无状态原则的案例,例如3-Legged
OAuth,API调用速度限制等。但照旧要硬着头皮确保服务器中不必要在多少个请求下保持利用状态。

可缓存

  在万维网上,客户端能够缓存页面的响应内容。由此响应都应隐式或显式的定义为可缓存的,若不足缓存则要幸免客户端在频仍呼吁后用旧数据或脏数据来响应。管理得当的缓存会部分地或完全地除了客户端和服务端之间的交互,进一步改正质量和延展性。

C-S架构

  统一接口使得客户端和服务端相互分开。关切分离意味什么?打个假诺,客户端不要求仓储数据,数据都留在服务端内部,那样使得客户端代码的可移植性得到了提高;而服务端不需要考虑用户接口和用户情状,那样一来服务端将进而简约易拓展。只要接口不改变,服务端和客户端可以独立地开展研发和替换。

支行系统

  客户端寻常不可以注明自己是一向或者直接与端服务器举行连接。中介服务器可以由此启用负载均衡或提供共享缓存来进步系统的延展性。分层时一致要考虑安全策略。

按需编码(可选)

  服务端通过传输可举办逻辑给客户端,从而为其暂时拓展和定制功用。相关的例证有编译组件Java
applets和客户端脚本JavaScript。

  听从上述标准,与REST架构风格保持一致,能让各样分布式超媒系列统所有梦想的自然属性,比如高品质,延展性,简洁,可变性,可视化,可移植性和可依赖性。

  提醒:REST架构中的统筹准则中,唯有按需编码为可选项。倘若某个服务违反了别的随意一项准则,严谨意思上不可能称之为RESTful风格。

 

REST神速提示

  (依照地点提到的四个规格)不管在技术上是否RESTful的,这里有部分近似REST概念的提议。遵循它们,能够完成更好、更使得的劳动:

行使HTTP动词表示一些意义

  任何API的使用者可以发送GET、POST、PUT和DELETE请求,它们很大程度明确了所给请求的目标。同时,GET请求不可以更改任何秘密的资源数量。测量和跟踪仍可能爆发,但只会更新数据而不会更新由URI标识的资源数量。

理所当然的资源名

  合理的资源名称或者路径(如/posts/23而不是/api?type=posts&id=23)可以更明确一个伸手的目标。使用URL查询串来过滤数据是很好的方式,但不应该用于固定资源名称。

  适当的资源名称为服务端请求提供上下文,增添服务端API的可领会性。通过URI名称分层地查看资源,可以给使用者提供一个协调的、简单精通的资源层次,以在他们的应用程序上选取。资源名称应当是名词,幸免为动词。使用HTTP方法来指定请求的动作部分,能让事情更是的显然。

XML和JSON

  提议默许支持json,并且,除非花费很惊人,否则就同时协助json和xml。在优异图景下,让使用者仅经过改变扩充名.xml和.json来切换类型。其余,对于支撑ajax风格的用户界面,一个被卷入的响应是不行有协理的。提供一个被装进的响应,在默许的要么有单独伸张名的状态下,例如:.wjson和.wxml,申明客户端请求一个被卷入的json或xml响应(请参见上边的卷入响应)。

  “标准”中对json的渴求很少。并且这个需要只是语法性质的,无关内容格式和布局。换句话说,REST服务端调用的json响应是说道的一有的——在专业中向来不有关描述。更加多关于json数据格式可以在http://www.json.org/上找到。

  关于REST服务中xml的拔取,xml的科班和预订除了利用语法正确的竹签和文本外没有任何的功效。越发地,命名空间不是也不该是被运用在REST服务端的上下文中。xml的回到更类似于json——简单、不难阅读,没有形式和命名空间的底细突显——仅仅是数据和链接。即便它比那更复杂的话,参看本节的首先段——使用xml的基金是惊心动魄的。鉴于大家的经验,很少有人利用xml作为响应。在它被统统淘汰从前,那是最终一个可被肯定的地点。

创设适当粒度的资源

  一初阶,系统中模仿底层应用程序域或数据库架构的API更便于被创建。最终,你会愿意将那个劳务都整合到共同——利用多项底层资源收缩通讯量。在创造独立的资源之后再创立更大粒度的资源,比从更大的合集中创立较大粒度的资源进一步简单一些。从局部小的简单定义的资源开头,创建CRUD(增删查改)功用,可以使资源的创立变得更便于。随后,你可以创制这几个依据用例和削减通讯量的资源。

设想连通性

  REST的原理之一就是连通性——通过超媒体链接完成。当在响应中回到链接时,api变的更具备自描述性,而在向来不它们时服务端如故可用。至少,接口本身可以为客户端提供什么样寻找数据的参照。其余,在通过POST方法创制资源时,还足以应用头地方包蕴一个链接。对于响应中协理分页的汇集,”first”、
“last”、”next”、和”prev”链接至少是老大管用的。

 

定义

幂等性

  不要从字面意思来领会什么是幂等性,恰恰相反,那与一些功用紊乱的天地毫无干系。下边是源于维基百科的表达:

在电脑科学中,术语幂等用于更完美地描述一个操作,三回或频繁执行该操作暴发的结果是一律的。按照使用的上下文,那说不定有例外的含义。例如,在方式或者子例程调用装有副成效的情事下,意味着在率先调用之后被涂改的事态也有限支撑不变。

  从REST服务端的角度来看,由于操作(或服务端调用)是幂等的,客户端可以用重新的调用而爆发同样的结果——在编程语言中操作像是一个”setter”(设置)方法。换句话说,就是行使多少个一律的乞求与利用单个请求效果一样。注意,当幂等操作在服务器上发出同样的结果(副成效),响应本身也许是例外的(例如在四个请求之间,资源的景观恐怕会变动)。

  PUT和DELETE方法被定义为是幂等的。查看http请求中delete动词的告诫音讯,可以参照下文的DELETE部分。GET、HEAD、OPTIO和TRACE方法自从被定义为平安的措施后,也被定义为幂等的。参照上面关于安全的段子。

安全

  来自维基百科:

有些方法(例如GET、HEAD、OPTIONS和TRACE)被定义为安全的措施,那意味着它们仅被用于新闻搜索,而不可能更改服务器的景象。换句话说,它们不会有副成效,除了相对来说无害的震慑如日志、缓存、横幅广告或计数服务等。任意的GET请求,不考虑选取状态的上下文,都被认为是高枕无忧的。

  可想而知,安全意味着调用的不二法门不会挑起副作用。因而,客户端可以屡屡使用安全的伸手而不用担心对服务端爆发任何副成效。那意味服务端必须遵从GET、HEAD、OPTIONS和TRACE操作的平安概念。否则,除了对消费端爆发模糊外,它还会促成Web缓存,搜索引擎以及任何活动代理的题材——那将在服务器上暴发意想不到的后果。

  按照定义,安全操作是幂等的,因为它们在服务器上爆发相同的结果。

  安全的点子被达成为只读操作。然则,安全并不代表服务器必须每便都回来相同的响应。

 

HTTP动词

  Http动词首要听从“统一接口”规则,并提需要大家相应的按照名词的资源的动作。最敬重依然最常用的http动词(或者叫做方法,那样称呼可能更恰当些)有POST、GET、PUT和DELETE。这么些分别对应于创制、读取、更新和删除(CRUD)操作。也有不可胜数任何的动词,然则利用频率比较低。在那一个应用较少的艺术中,OPTIONS和HEAD往往采取得越来越多。

GET

  HTTP的GET方法用于检索(或读取)资源的数据。在科学的乞求路径下,GET方法会重回一个xml或者json格式的数目,以及一个200的HTTP响应代码(表示正确重回结果)。在错误情形下,它一般再次回到404(不存在)或400(错误的伏乞)。

  例如:

*  GET http://www.example.com/customers/12345*
  GET http://www.example.com/customers/12345/orders
  GET http://www.example.com/buckets/sample

  根据HTTP的设计规范,GET(以及附带的HEAD)请求仅用于读取数据而不改动多少。由此,这种应用办法被认为是高枕无忧的。也就是说,它们的调用没有数量修改或污染的高风险——调用1次和调用10次照旧没有被调用的效益等同。别的,GET(以及HEAD)是幂等的,那意味着使用七个相同的伸手与行使单个的请求最后都有所同等的结果。

  不要通过GET揭示不安全的操作——它应当永远都无法改改服务器上的其它资源。

PUT

  PUT平时被用来立异资源。通过PUT请求一个已知的资源URI时,须要在哀告的body中蕴藏对原本资源的换代数据。

  不过,在资源ID是由客服端而非服务端提供的意况下,PUT同样可以被用来创设资源。换句话说,倘诺PUT请求的URI中蕴藏的资源ID值在服务器上不存在,则用于成立资源。同时伸手的body中务必含有要开创的资源的数据。有人认为那会时有暴发歧义,所以唯有真的必要,使用那种方法来创建资源应该被慎用。

  或者大家也得以在body中提供由客户端定义的资源ID然后使用POST来创制新的资源——倘诺请求的URI中不包涵要创制的资源ID(参见上边POST的有些)。

  例如:

*  PUT http://www.example.com/customers/12345*
  PUT http://www.example.com/customers/12345/orders/98765
  PUT http://www.example.com/buckets/secret\_stuff

  当使用PUT操作更新成功时,会重临200(或者再次回到204,表示回去的body中不带有其他内容)。若是利用PUT请求成立资源,成功重临的HTTP状态码是201。响应的body是可选的——即使提供的话将会消耗更加多的带宽。在成立资源时从没要求通过底部的岗位再次来到链接,因为客户端已经安装了资源ID。请参见上面的重返值部分。

  PUT不是一个安全的操作,因为它会修改(或创建)服务器上的动静,但它是幂等的。换句话说,若是您使用PUT创制或者更新资源,然后再次调用,资源如故存在并且状态不会发生变化。

  例如,即使在资源增量计数器中调用PUT,那么那几个调用方法就不再是幂等的。那种景色有时候会暴发,且可能可以验证它是非幂等性的。可是,指出维持PUT请求的幂等性。并强烈指出非幂等性的央浼使用POST。

POST

  POST请求日常被用来创建新的资源,越发是被用来创设从属资源。从属资源即归属于其他资源(如父资源)的资源。换句话说,当创设一个新资源时,POST请求发送给父资源,服务端负责将新资源与父资源拓展关联,并分配一个ID(新资源的URI),等等。

  例如:

  POST http://www.example.com/customers
  POST http://www.example.com/customers/12345/orders

  当创设成功时,重返HTTP状态码201,并顺便一个职位头信息,其中带有指向初步创立的资源的链接。

  POST请求既不是高枕无忧的又不是幂等的,因而它被定义为非幂等性资源请求。使用三个一样的POST请求很可能会招致创立五个饱含相同音讯的资源。

PUT和POST的创制比较

  不言而喻,大家提出选用POST来创制资源。当由客户端来决定新资源有着何等URI(通过资源名称或ID)时,使用PUT:即假设客户端知道URI(或资源ID)是何许,则对该URI使用PUT请求。否则,当由服务器或服务端来支配创办的资源的URI时则选用POST请求。换句话说,当客户端在创立此前不精晓(或不可能理解)结果的URI时,使用POST请求来创制新的资源。

DELETE

  DELETE很不难通晓。它被用来根据URI标识删除资源。

  例如:

  DELETE http://www.example.com/customers/12345
  DELETE http://www.example.com/customers/12345/orders
  DELETE http://www.example.com/buckets/sample

  当删除成功时,再次回到HTTP状态码200(表示正确),同时会顺手一个响应体body,body中或者含有了去除项的多寡(这会占用部分互联网带宽),或者封装的响应(参见上面的再次回到值)。也得以重回HTTP状态码204(表示无内容)表示不曾响应体。可想而知,可以回来状态码204表示从未响应体,或者再次来到状态码200同时附带JSON风格的响应体。

  依照HTTP规范,DELETE操作是幂等的。假若您对一个资源开展DELETE操作,资源就被移除了。在资源上往往调用DELETE最终致使的结果都一模一样:即资源被移除了。但假使将DELETE的操成效于计数器(资源内部),则DETELE将不再是幂等的。如前方所述,只要数据没有被更新,计算和测量的用法如故可被认为是幂等的。提议非幂等性的资源请求使用POST操作。

  但是,那里有一个有关DELETE幂等性的警戒。在一个资源上第二次调用DELETE往往会回去404(未找到),因为该资源已经被移除了,所以找不到了。那使得DELETE操作不再是幂等的。假如资源是从数据库中除去而不是被不难地标记为除去,这种气象须要适度让步。

  下表计算出了重点HTTP的方式和资源URI,以及引进的再次回到值:

HTTP请求

/customers

/customers/{id}

GET

200(正确),用户列表。使用分页、排序和过滤大导航列表。

200(正确),查找单个用户。如果ID没有找到或ID无效则赶回404(未找到)。

PUT

404(未找到),除非您想在一切集合中更新/替换每个资源。

200(正确)或204(无内容)。即使没有找到ID或ID无效则赶回404(未找到)。

POST

201(成立),带有链接到/customers/{id}的岗位头消息,包蕴新的ID。

404(未找到)

DELETE

404(未找到),除非您想删除所有集合——经常不被允许。

200(正确)。假设没有找到ID或ID无效则赶回404(未找到)。

 

资源命名

  除了适当地动用HTTP动词,在开立一个方可领悟的、易于使用的Web服务API时,资源命名可以说是最富有争议和最要紧的概念。一个好的资源命名,它所对应的API看起来更直观并且易于使用。相反,即职责名不佳,同样的API会令人感到很鲁钝并且难以精晓和动用。当你须求为你的新API成立资源URL时,那里有一对小技巧值得借鉴。

  从本质上讲,一个RESTFul
API最后都足以被简单地看成是一堆URI的集纳,HTTP调用那些URI以及部分用JSON和(或)XML表示的资源,它们中有很多涵盖了互相关联的链接。RESTful的可寻址能力根本看重URI。每个资源都有投机的地点或URI——服务器能提供的每一个实惠的新闻都可以视作资源来公开。统一接口的尺度部分地经过URI和HTTP动词的咬合来缓解,并符合利用规范和约定。

  在支配你系统中要利用的资源时,使用名词来命名那个资源,而不是用动词或动作来定名。换句话说,一个RESTful
URI应该提到到一个有血有肉的资源,而不是涉嫌到一个动作。此外,名词还兼具局地动词没有的性能,那也是另一个斐然的要素。

  一些资源的例子:

  • 系统的用户
  • 学生注册的科目
  • 一个用户帖子的年华轴
  • 关爱其余用户的用户
  • 一篇有关骑马的文章

  服务套件中的每个资源最少有一个URI来标识。若是这一个URI能表示肯定的含义并且可以尽量描述它所表示的资源,那么它就是一个最好的命名。URI应该有着可预测性和支行结构,那将拉动进步它们的可精晓性和可用性的:可预测指的是资源应该和称号保持一致;而分层指的是数量颇具关系上的结构。那并非REST规则或正式,然则它加重了对API的定义。

  RESTful
API是提须求消费端的。URI的称呼和布局应当将它所抒发的意义传达给顾客。平日大家很难通晓多少的界线是怎么,不过从您的数目上你应有很有可能去品味找到要赶回给客户端的数码是何许。API是为客户端而规划的,而不是为您的多少。

  要是大家今天要讲述一个包涵客户、订单,列表项,产品等效果的订单系统。考虑一下我们该怎么来叙述在那几个服务中所涉及到的资源的URIs:

资源URI示例

  为了在系统中插入(创制)一个新的用户,大家可以运用:

  POST http://www.example.com/customers

 

  读取编号为33245的用户音信:

  GET http://www.example.com/customers/33245

  使用PUT和DELETE来请求相同的URI,可以创新和删除数据。

 

  上边是对成品有关的URI的一部分提出:

  POST http://www.example.com/products

  用于创建新的产品。

 

  GET|PUT|DELETE http://www.example.com/products/66432

  分别用于读取、更新、删除编号为66432的制品。

 

  那么,怎么着为用户创制一个新的订单呢?

  一种方案是:

  POST http://www.example.com/orders

  那种方法可以用来成立订单,但缺少相应的用户数据。

  

  因为我们想为用户创立一个订单(注意之间的涉及),那么些URI可能不够直观,下边这几个URI则更清晰一些:

  POST http://www.example.com/customers/33245/orders

  现在大家清楚它是为编号33245的用户创设一个订单。

 

  那上边这一个请求再次回到的是怎么呢?

  GET http://www.example.com/customers/33245/orders

  可能是一个编号为33245的用户所创办或具有的订单列表。注意:大家得以屏蔽对该URI举办DELETE或PUT请求,因为它的操作对象是一个会面。

 

  继续深刻,那下面这么些URI的乞请又象征怎样呢?

  POST http://www.example.com/customers/33245/orders/8769/lineitems

  可能是(为编号33245的用户)增添一个号码为8769的订单条目。没错!要是应用GET情势呼吁那么些URI,则会重回那一个订单的有着条条框框。可是,要是这个条款与用户音讯无关,大家将会提供POST
www.example.com/orders/8769/lineitems
这个URI。

  从再次回到的那些条款来看,指定的资源可能会有多个URIs,所以我们可能也亟须要提供那样一个URI
GET
http://www.example.com/orders/8769
,用来在不精通用户ID的情景下基于订单ID来询问订单。

 

  更进一步:

  GET http://www.example.com/customers/33245/orders/8769/lineitems/1

  可能只回去同个订单中的第二个条目。

  现在您应有了然什么是分层结构了。它们并不是严苛的平整,只是为了保障在您的劳务中那么些强制的结构可以更便于被用户所知晓。与富有软件开发中的技能一样,命名是水到渠成的首要。

  

  多看有些API的演示并学会控制这么些技术,和你的队友一起来完善你API资源的URIs。那里有一部分APIs的例证:

资源命名的反例

  前边大家早就研商过一些适龄的资源命名的事例,然则有时一些反面的例子也很有教育意义。上边是有的不太具有RESTful风格的资源URIs,看起来相比较散乱。那么些都是一无是处的事例! 

  首先,一些serivices往往使用单一的URI来指定服务接口,然后经过询问参数来指定HTTP请求的动作。例如,要创新编号12345的用户新闻,带有JSON
body的乞请可能是那样:

  GET
http://api.example.com/services?op=update\_customer&id=12345&format=json

  固然地点URL中的”services”的这几个节点是一个名词,但以此URL不是自解释的,因为对于具有的伸手而言,该URI的层级结构都是千篇一律的。别的,它应用GET作为HTTP动词来推行一个创新操作,那简直就是反人类(甚至是生命垂危的)。

  上面是此外一个翻新用户的操作的例子:

  GET http://api.example.com/update\_customer/12345

  以及它的一个变种:

  GET http://api.example.com/customers/12345/update

  你会常常见到在其余开发者的劳动套件中有那些这么的用法。可以看到,那些开发者试图去创制RESTful的资源名称,而且早已有了一部分提高。可是你照样可以分辨出URL中的动词短语。注意,在那些URL中大家不须要”update”那些词,因为大家得以凭借HTTP动词来成功操作。上面这些URL正好表达了这或多或少:

  PUT http://api.example.com/customers/12345/update

  这一个请求同时存在PUT和”update”,那会对消费者暴发迷惑!那里的”update”指的是一个资源吗?由此,那里大家费些口舌也是期望您可见知情……

复数

  让大家来研商一下复数和“单数”的争持…还没听说过?但这种争议确实存在,事实上它可以归纳为那么些难题……

  在您的层级结构中URI节点是还是不是需求被命名为单数或复数情势吗?举个例证,你用来探寻用户资源的URI的命名是还是不是要求像上面这样:

  GET http://www.example.com/customer/33245

  或者:

  GET http://www.example.com/customers/33245

  二种形式都没难点,但常见大家都会挑选使用复数命名,以使得你的API
URI在装有的HTTP方法中保持一致。原因是基于那样一种考虑:customers是劳动套件中的一个成团,而ID33245的这些用户则是以此集合中的其中一个。

  按照那些规则,一个选取复数格局的多节点的URI会是那般(注意粗体部分):

  GET
http://www.example.com/**customers**/33245/**orders**/8769/**lineitems**/1

  “customers”、“orders”以及“lineitems”这几个URI节点都选用的是复数格局。

  那意味你的每个根资源只要求四个宗旨的URL就可以了,一个用于创制集合内的资源,另一个用来根据标识符获取、更新和删除资源。例如,以customers为例,创造资源得以选取上面的URL举办操作:

  POST http://www.example.com/customers

  而读取、更新和删除资源,使用上面的URL操作:

  GET|PUT|DELETE http://www.example.com/customers/{id}

  正如前方提到的,给定的资源可能有四个URI,但作为一个细微的完全的增删改查作用,利用四个简易的URI来拍卖就够了。

  或许你会问:是还是不是在有点情状下复数没有意思?嗯,事实上是如此的。当没有集合概念的时候(此时复数没有意思)。换句话说,当资源只有一个的景色下,使用单数资源名称也是足以的——即一个单一的资源。例如,要是有一个纯粹的完全体署资源,你可以选拔一个单数名称来表示:

  GET|PUT|DELETE http://www.example.com/configuration

  注意这里缺乏configuration的ID以及HTTP动词POST的用法。借使每个用户有一个计划来说,那么那个URL会是如此:

  GET|PUT|DELETE
http://www.example.com/customers/12345/configuration

  同样令人瞩目那里没有点名configuration的ID,以及从未给定POST动词的用法。在那多个例子中,可能也会有人以为选拔POST是实惠的。好吧…

 

回到表征

  正如前方提到的,RESTful接口协理各样资源特色,包涵JSON和XML,以及被包裹的JSON和XML。提出JSON作为默许表征,不过服务端应该允许客户端指定其余表征。

  对于客户端请求的特性格式,大家可以在Accept头通过文件扩大名来展开点名,也足以透过query-string等任何方法来指定。理想图景下,服务端可以支撑具有这么些艺术。可是,现在正式更赞成于通过类似于文件增添名的主意来开展点名。由此,建议服务端至少必要辅助使用文件扩张名的章程,例如“.json”,“.xml”以及它们的包裹版本“.wjon”,“.wxml”。

  通过那种方法,在URI中指定再次回到表征的格式,可以压实URL的可知性。例如,GET
http://www.example.com/customers.xml
将回来customer列表的XML格式的表征。同样,GET
http://www.example.com/customers.json
将重返一个JSON格式的特性。那样,即便是在最基础的客户端(例如“curl”),服务使用起来也会进一步便利。推荐应用那种方法。

  别的,当url中没有包罗格式表明时,服务端应该回到默许格式的特性(即使为JSON)。例如:

  GET http://www.example.com/customers/12345

  GET http://www.example.com/customers/12345.json

  以上两者再次回到的ID为12345的customer数据均为JSON格式,那是服务端的默许格式。

  GET http://www.example.com/customers/12345.xml

  倘诺服务端扶助的话,以上请求重临的ID为12345的customer数据为XML格式。要是该服务器不支持XML格式的资源,将赶回一个HTTP
404的一无所能。

  使用HTTP
Accept头被普遍认为是一种更优雅的办法,并且符合HTTP的正统和意义,客户端可以通过那种办法来报告HTTP服务端它们可支撑的数据类型有啥。不过,为了利用Accept头,服务端要同时匡助封装和未封装的响应,你必须贯彻自定义的档次——因为这几个格式不是正规的连串。那大大增添了客户端和服务端的复杂性。请参见RFC
2616的14.1节有关Accept头的详细新闻(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1)。使用文件伸张名来指定数量格式是最简便间接的法门,用最少的字符就可以形成,并且协理脚本操作——无需选择HTTP头。

  平日当大家关系REST服务,跟XML是非亲非故的。纵然服务端帮助XML,也大约一直不人指出在REST中使用XML。XML的专业和公约在REST中不太适用。越发是它连命名空间都未曾,就更不应该在RESTful服务系列中采纳了。那只会使工作变得更复杂。所以回来的XML看起来更像JSON,它大约易读,没有情势和命名空间的限制,换句话来说是无标准的,易于解析。

资源通过链接的可发现性(HATEOAS续)

  REST率领规范之一(根据联合接口规范)是application的状态通过hypertext(超文本)来传输。那就是我们普通所说的Hypertext
As The Engine of Application State
(即HATEOAS,用超文本来作为应用程序状态机),大家在“REST是什么”一节中也提到过。

  依照罗伊Fielding在他的博客中的描述(http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertextdriven),REST接口中最重大的局地是超文本的施用。别的,他还提议,在交付任何有关的信息往日,一个API应该是可用和可领略的。也就是说,一个API应当可以由此其链接导航到多少的依次部分。不指出只回去纯数据。

  可是当下的业界先驱们并从未平常应用这种做法,这反映了HATEOAS仅仅在成熟度模型中的使用率更高。纵观众多的服务序列,它们基本上再次来到越来越多的多寡,而回到的链接却很少(或者没有)。那是违反Fielding的REST约定的。Fielding说:“音信的每一个可寻址单元都率领一个地点……查询结果应当突显为一个饱含摘要音讯的链接清单,而不是目的数组。”

  另一方面,简单阴毒地将所有链接集合重回会大大影响互联网带宽。在其实意况中,按照所需的口径或应用情状,API接口的通讯量要基于服务器响应中国足球社团超级联赛文本链接所涵盖的“摘要”数量来平衡。

  同时,丰裕利用HATEOAS可能会伸张落成的错综复杂,并对服务客户端暴发显然的负责,这一定于下跌了客户端和劳务器端开发人士的生产力。由此,当务之急是要平衡超链接服务实施和现有可用资源之间的难题。

  超链接最小化的做法是在最大限度地裁减客户端和服务器之间的耦合的还要,升高服务端的可用性、可操纵性和可掌握性。那个最小化提出是:通过POST创造资源并从GET请求再次来到集合,对于有分页的图景前面大家会涉及。

小小的化链接推荐

  在create的用例中,新建资源的URI(链接)应该在Location响应头中回到,且响应中央是空的——或者只含有新建资源的ID。

  对于从服务端再次来到的特色集合,每个表征应该在它的链接集合中教导一个微小的“自身”链接属性。为了有利于分页操作,其余的链接可以置身一个独自的链接集合中回到,要求时得以分包“第一页”、“上一页”、“下一页”、“最终一页”等音信。

  参照下文链接格式有的的例子获取越来越多消息。

链接格式

  参照整个链接格式的正统,提议听从一些看似Atom、AtomPub或Xlink的风格。JSON-LD也不错,但并从未被大面积使用(如果已经被用过)。近期标准最常见的措施是应用含有”rel”元素和包蕴资源全体URI的”href”元素的Atom链接格式,不带有其余身份验证或询问字符串参数。”rel”元素得以涵盖标准值”alternate”、”related”、”self”、”enclosure”和”via”,还有分页链接的“第一页”、“上一页”、“下一页”,“最终一页”。在须求时可以自定义并丰富应用它们。

  一些XML
Atom格式的定义对于用JSON格式表示的链接来说是于事无补的。例如,METHOD属性对于一个RESTful资源来说是不须要的,因为对于一个加以的资源,在装有协助的HTTP方法(CRUD行为)中,资源的URI都是同一的——所以单独列出那一个是绝非须求的。

  让我们举一些具体的事例来更是说明这点。上边是调用创立新资源的请求后的响应:

  POST http://api.example.com/users

  下边是响应头集合中含有成立新资源的URI的Location部分:

HTTP/1.1 201 CREATED 
Status: 201 
Connection: close 
Content-Type: application/json; charset=utf-8 
Location: http://api.example.com/users/12346

  再次来到的body可以为空,或者隐含一个被卷入的响应(见下文封装响应)。

  下边的事例通过GET请求获取一个不带有分页的表征集合的JSON响应:

{
  "data": [
    {
      "user_id": "42",
      "name": "Bob",
      "links": [
        {
          "rel": "self",
          "href": "http://api.example.com/users/42"
        }
      ]
    },
    {
      "user_id": "22",
      "name": "Frank",
      "links": [
        {
          "rel": "self",
          "href": "http://api.example.com/users/22"
        }
      ]
    },
    {
      "user_id": "125",
      "name": "Sally",
      "links": [
        {
          "rel": "self",
          "href": "http://api.example.com/users/125"
        }
      ]
    }
  ]
}

  注意,links数组中的每一项都带有一个针对性“自身(self)”的链接。该数组还可能还蕴藏其余关系,如children、parent等。

  最终一个例子是由此GET请求获取一个含有分页的特点集合的JSON响应(每页突显3项),大家付出第三页的数额:

{
  "data": [
    {
      "user_id": "42",
      "name": "Bob",
      "links": [
        {
          "rel": "self",
          "href": "http://api.example.com/users/42"
        }
      ]
    },
    {
      "user_id": "22",
      "name": "Frank",
      "links": [
        {
          "rel": "self",
          "href": "http://api.example.com/users/22"
        }
      ]
    },
    {
      "user_id": "125",
      "name": "Sally",
      "links": [
        {
          "rel": "self",
          "href": "http://api.example.com/users/125"
        }
      ]
    }
  ],
  "links": [
    {
      "rel": "first",
      "href": "http://api.example.com/users?offset=0&limit=3"
    },
    {
      "rel": "last",
      "href": "http://api.example.com/users?offset=55&limit=3"
    },
    {
      "rel": "previous",
      "href": "http://api.example.com/users?offset=3&limit=3"
    },
    {
      "rel": "next",
      "href": "http://api.example.com/users?offset=9&limit=3"
    }
  ]
}

  在这一个例子中,响应中用来分页的links集合中的每一项都包括一个针对“自身(self)”的链接。那里可能还会有一部分事关到聚集的别的链接,但都与分页本身毫无干系。简单的说,那里有五个地方含有links。一个就是data对象中所包括的会聚(那些也是接口要回来给客户端的数码表征集合),其中的每一项至少要包罗一个针对“自身(self)”的links集合;另一个则是一个独门的靶子links,其中包含和分页相关的链接,该部分的内容适用于漫天集合。

  对于因此POST请求成立资源的处境,必要在响应头中包罗一个事关新建对象链接的Location

装进响应

   服务器可以在响应中并且重返HTTP状态码和body。有那几个JavaScript框架没有把HTTP状态响应码重返给最终的开发者,那频仍会导致客户端无法根据景况码来确定具体的一坐一起。别的,固然HTTP规范中有很各类响应码,不过往往只有个别客户端会关切那几个——常常大家只在乎”success”、”error”或”failture”。由此,将响应内容和响应状态码封装在蕴藏响应音讯的特点中,是有必不可少的。

  OmniTI
实验室有诸如此类一个指出,它被称呼JSEND响应。越来越多音信请参考http://labs.omniti.com/labs/jsend。别的一个提案是由DouglasCrockford提议的,可以查阅那里http://www.json.org/JSONRequest.html

  这一个提案在实践中并不曾完全涵盖所有的场所。基本上,现在最好的做法是根据以下属性封装常规(非JSONP)响应:

  • code——包括一个平头品类的HTTP响应状态码。
  • status——蕴含文本:”success”,”fail”或”error”。HTTP状态响应码在500-599之内为”fail”,在400-499时期为”error”,其余均为”success”(例如:响应状态码为1XX、2XX和3XX)。
  • message——当状态值为”fail”和”error”时有效,用于体现错误音信。参照国际化(il8n)标准,它能够蕴含消息号或者编码,可以只包涵其中一个,或者同时富含并用分隔符隔开。
  • data——包涵响应的body。当状态值为”fail”或”error”时,data仅包罗错误原因或越发名称。

  下边是一个回去success的包装响应:

{
  "code": 200,
  "status": "success",
  "data": {
    "lacksTOS": false,
    "invalidCredentials": false,
    "authToken": "4ee683baa2a3332c3c86026d"
  }
}

  再次来到error的包裹响应:

{
  "code": 401,
  "status": "error",
  "message": "token is invalid",
  "data": "UnauthorizedException"
}

  这多个包装响应对应的XML如下:

<response>
    <code>200</code>
    <status>success</status>
    <data class="AuthenticationResult">
        <lacksTOS>false</lacksTOS>
        <invalidCredentials>false</invalidCredentials>
        <authToken>1.0|idm|idm|4ee683baa2a3332c3c86026d</authToken>
    </data>
</response>

  和:

<response>
    <code>401</code>
    <status>error</status>
    <message>token is invalid</message>
    <data class="string">UnauthorizedException</data>
</response>

处理跨域难题

   大家都听说过有关浏览器的同源策略或同源性须要。它指的是浏览器只可以请求当前正在显示的站点的资源。例如,如果当前正值显示的站点是www.Example1.com,则该站点无法对www.Example.com提倡呼吁。鲜明那会潜移默化站点访问服务器的措施。

  如今有五个被广大接受的支撑跨域请求的法门:JSONP和跨域资源共享(CORS)。JSONP或“填充的JSON”是一种接纳情势,它提供了一个艺术请求来自不一样域中的服务器的数据。其行事措施是从服务器重回任意的JavaScript代码,而不是JSON。客户端的响应由JavaScript解析器举办解析,而不是一向解析JSON数据。别的,CORS是一种web浏览器的技能专业,它为web服务器定义了一种艺术,从而允许服务器的资源得以被不相同域的网页访问。CORS被视作是JSONP的新式替代品,并且可以被所有现代浏览器协助。由此,不提议利用JSONP。任何动静下,推荐选用CORS。

支持CORS

  在服务端完结CORS很粗略,只须求在殡葬响应时顺手HTTP头,例如: 

Access-Control-Allow-Origin: *

  唯有在数额是公物使用的情况下才会将访问来源设置为”*”。半数以上景况下,Access-Control-Allow-Origin头应该指定哪些域可以倡导一个CORS请求。唯有须求跨域访问的URL才设置CORS头。

Access-Control-Allow-Origin: http://example.com:8080
http://foo.example.com

  以上Access-Control-Allow-Origin头中,被安装为只同意受依赖的域可以访问。

Access-Control-Allow-Credentials: true

  只在急需时才使用方面这几个header,因为要是用户已经报到的话,它会同时发送cookies/sessions。

  那些headers可以透过web服务器、代理来拓展配置,或者从服务器本身发送。不推荐在服务端完毕,因为很不灵便。或者,能够应用方面的第三种艺术,在web服务器上配置一个用空格分隔的域的列表。更加多关于CORS的始末可以参考那里:http://enable-cors.org/

支持JSONP

  JSONP通过应用GET请求避开浏览器的限制,从而完成对所有服务的调用。其行事原理是请求方在呼吁的URL上添加一个字符串查询参数(例如:jsonp=”jsonp_callback”),其中“jsonp”参数的值是JavaScript函数名,该函数在有响应重返时将会被调用。

  由于GET请求中绝非包蕴请求体,JSONP在使用时有着严重的局限性,由此数据必须透过字符串查询参数来传递。同样的,为了帮忙PUT,POST和DELETE方法,HTTP方法必须也通过字符串查询参数来传递,类似_method=POST那种格局。像这么的HTTP方法传送格局是不引进应用的,那会让服务处于安全风险之中。

  JSONP平常在有的不协理CORS的老旧浏览器中使用,即使要改成援助CORS的,会潜移默化总体服务器的架构。或者大家也可以透过代理来兑现JSONP。不问可知,JSONP正在被CORS所代替,我们理应尽量地行使CORS。

  为了在服务端援助JSONP,在JSONP字符串查询参数传递时,响应必需要履行以下那一个操作:

  1. 响应体必须封装成一个参数传递给jsonp中指定的JavaScript函数(例如:jsonp_callback(“<JSON
    response body>”))。
  2. 始终重临HTTP状态码200(OK),并且将真实的图景作为JSON响应中的一有些再次来到。

  此外,响应体中平常必须含有响应头。这使得JSONP回调方法须要根据响应体来确定响应处理形式,因为它自身不可以获知真实的响应头和景色值。

  上面的例证是按照上述办法封装的一个回去error状态的jsonp(注意:HTTP的响应状态是200):

jsonp_callback("{'code':'404', 'status':'error','headers':[],'message':'resource XYZ not
found','data':'NotFoundException'}")

  成功创办后的响应类似于那般(HTTP的响应状态仍是200):

jsonp_callback("{'code':'201', 'status':'error','headers':
[{'Location':'http://www.example.com/customers/12345'}],'data':'12345'}")

 

询问,过滤和分页

  对于大数据集,从带宽的角度来看,限制重返的数据量是越发紧要的。而从UI处理的角度来看,限制数据量也同样首要,因为UI常常只能够显示大数据汇总的一小部分数额。在数据集的拉长速度不确定的情形下,限制默认重临的数据量是很有必不可少的。以推特(TWTR.US)为例,要博得某个用户的推文(通过个人主页的时间轴),借使没有越发指定,请求默认只会重回20条记下,固然系统最多能够回来200条记下。

  除了限制重回的数据量,大家还亟需考虑什么对命局据集进行“分页”或下拉滚动操作。创造数量的“页码”,重临大数量列表的已知片段,然后标出数据的“前一页”和“后一页”——这一行事被叫作分页。此外,我们兴许也急需指定响应旅长包含哪些字段或性质,从而限制重回值的数目,并且大家盼望最终可以透过一定值来展开查询操作,并对再次来到值举办排序。

  有三种首要的法门来还要限定查询结果和实施分页操作。首先,大家可以建立一个目录方案,它可以以页码为导向(请求中要交给每一页的记录数及页码),或者以记录为导向(请求中一向提交第一条记下和终极一条记下)来规定重临值的苗头地方。举个例子,那两种办法分别代表:“给出第五页(假使每页有20条记下)的笔录”,或“给出第100到第120条的记录”。

  服务端将依照运作体制来开展切分。有些UI工具,比如Dojo
JSON会选拔模仿HTTP规范使用字节范围。假如服务端协助out of
box(即开箱即用功用),则前端UI工具和后端服务中间无需任何转换,那样使用起来会很有利。

  下文将介绍一种办法,既能够帮忙Dojo那样的分页情势(在请求头中付出记录的限制),也能协助使用字符串查询参数。那样一来服务端将变得进一步灵敏,既能够动用类似Dojo一样先进的UI工具集,也得以选拔简易直接的链接和标签,而无需再为此扩张复杂的开发工作。但借使服务不直接扶助UI功用,可以考虑不要在请求头中付出记录范围。

  要专门提出的是,大家并不推荐在享有服务中采纳查询、过滤和分页操作。并不是有着资源都默许协理那些操作,唯有某些特定的资源才支撑。服务和资源的文档应当表达什么接口支持这一个扑朔迷离的机能。

结果限制

  “给出第3到第55条的笔录”,那种请求数据的章程和HTTP的字节范围规范更平等,由此大家得以用它来标识Range
header。而“从第2条记下初始,给出最多20条记下”那种艺术更易于阅读和透亮,因而大家平常会用字符串查询参数的办法来表示。

  综上所述,推荐既支持采用HTTP Range
header,也支撑选用字符串查询参数——offset(偏移量)和limit(限制),然后在服务端对响应结果开展限定。注意,要是同时帮衬那两种格局,那么字符串查询参数的预先级要当先Range
header。

  那里您恐怕会有个疑问:“那三种方法效果相似,可是回到的数量不完全一致。那会不会令人歪曲呢?”恩…那是三个难题。首先要回答的是,那诚然会让人歪曲。关键是,字符串查询参数看起来更为清晰易懂,在营造和剖析时尤其有利于。而Range
header则越来越多是由机器来采纳(偏向于底层),它越是符合HTTP使用正规。

  不问可知,解析Range
header的工作会增加复杂度,相应的客户端在打造请求时也急需展开部分拍卖。而接纳单独的limit和offset参数会更为不难精晓和打造,并且不须要对开发人士有更加多的渴求。

用范围标记举行界定

  当用HTTP header而不是字符串查询参数来得到记录的限制时,Ranger
header应该通过以下内容来指定范围: 

  Range: items=0-24

  注意记录是从0早先的接连字段,HTTP规范中验证了怎么运用Range
header来请求字节。也就是说,如若要哀告数据集中的率先条记下,范围应当从0开头算起。上述的呼吁将会重临前25个记录,借使数据汇总至少有25条记下。

  而在服务端,通过检查请求的Range
header来确定该再次回到哪些记录。只要Range
header存在,就会有一个差不多的正则表达式(如”items=(\d+)-(\d+)”)对其举办分析,来博取要摸索的范围值。

用字符串查询参数举办限制

  字符串查询参数被看成Range
header的替代选择,它接纳offset和limit作为参数名,其中offset代表要询问的首先条记下编号(与上述的用于范围标记的items首个数字相同),limit代表记录的最大条数。下边的事例再次来到的结果与上述用范围标记的例子一样:

  GET http://api.example.com/resources?offset=0&limit=25

  Offset参数的值与Range
header中的类似,也是从0开头推测。Limit参数的值是重临记录的最大数目。当字符串查询参数中未指定limit时,服务端应当提交一个缺省的最大limit值,然则那一个参数的选取都亟待在文档中展开验证。

基于范围的响应

  对一个按照范围的伸手来说,无论是通过HTTP的Range
header依然经过字符串查询参数,服务端都应有有一个Content-Range
header来响应,以标明重回记录的条数和总记录数:

  Content-Range: items 0-24/66

  注意那里的总记录数(如本例中的66)不是从0初始总计的。假使要请求数据集中的最终几条记下,Content-Range
header的情节应当是那般:

  Content-Range: items 40-65/66

  依照HTTP的正规化,如若响应时总记录数未知或不便总结,也足以用星号(”*”)来取代(如本例中的66)。本例中响应头也可那般写:

  *Content-Range: items 40-65/**

  然而要留心,Dojo或一些别的的UI工具可能不帮助该符号。

分页

  上述措施通过请求方指定数据集的范围来界定重回结果,从而落成分页成效。上边的事例中总括有66条记下,倘使每页25条记下,要显得第二页数据,Range
header的情节如下:

  Range: items=25-49

  同样,用字符串查询参数表示如下:

  GET …?offset=25&limit=25

  服务端会相应地赶回一组数据,附带的Content-Range header内容如下:

  Content-Range: 25-49/66

  在大部动静下,那种分页格局都未曾难题。但偶尔会有那种情形,就是要回去的笔录数据不可以直接表示成多少集中的行号。还有就是有些数据集的变通很快,不断会有新的数目插入到多少集中,那样自然会招致分页出现难点,一些重新的数额或者会并发在差其他页中。

  按日期排列的数据集(例如推特feed)就是一种普遍的情形。尽管你要么得以对数据开展分页,但有时用”after”或”before”那样的显要字并与Range
header(或者与字符串查询参数offset和limit)同盟来促成分页,看起来会愈发从简易懂。

  例如,要得到给定时间戳的前20条评论:

  GET
http://www.example.com/remarks/home\_timeline?after=&lt;timestamp&gt

  Range: items=0-19

  GET
http://www.example.com/remarks/home\_timeline?before=&lt;timestamp&gt

*  Range: items=0-19*

  用字符串查询参数表示为:

  GET
http://www.example.com/remarks/home\_timeline?after=&lt;timestamp&gt;&offset=0&limit=20 

*  GET
http://www.example.com/remarks/home\_timeline?before=&lt;timestamp&gt;&offset=0&limit=20*

  有关在分化景观对时间戳的格式化处理,请参见下文的“日期/时间拍卖”。

  如果请求时从没点名要赶回的数目范围,服务端再次来到了一组默许数据或限制的最大数据集,那么服务端同时也应该在回去结果中含有Content-Range
header来和客户端进行确认。以地点个人主页的时刻轴为例,无论客户端是否指定了Range
header,服务端每趟都只回去20条记下。此时,服务端响应的Content-Range
header应该包括如下内容:

  Content-Range: 0-19/4125

  或 *Content-Range: 0-19/**

结果的过滤和排序

  针对重临结果,还索要考虑怎么在服务端对数据开展过滤和排列,以及怎么样按指定的顺序对子数据开展检索。这么些操作可以与分页、结果限制,以及字符串查询参数filter和sort等相结合,可以兑现强大的数据检索功效。

  再强调三次,过滤和排序都是纵横交叉的操作,不需求默许提要求持有的资源。下文将介绍怎么样资源需求提供过滤和排序。

过滤

  在本文中,过滤被定义为“通过一定的规则来规定必须求回去的数量,从而收缩重回的数目”。即使服务端扶助一套完整的相比运算符和复杂的原则格外,过滤操作将变得一定复杂。不过大家平常会利用部分概括的表明式,如starts-with(以…初步)或contains(包罗)来展开匹配,以担保重回数据的完整性。

  在大家初始研究过滤的字符串查询参数此前,必须先明了为何要使用单个参数而不是三个字符串查询参数。从根本上来说是为着减小参数名称的顶牛。我们早就有offsetlimitsort(见下文)参数了。要是可能的话还会有jsonpformat标识符,或许还会有afterbefore参数,那些都是在本文中关系过的字符串查询参数。字符串查询中动用的参数越来越多,就越可能造成参数名称的顶牛,而选用单个过滤参数则会将冲突的可能性降到最低。

  其它,从服务端也很不难仅经过单个的filter参数来判定请求方是或不是需求多少过滤效果。如若查询须要的复杂度增添,单个参数将更具备灵活性——可以友善树立一套效用完全的查询语法(详见下文OData注释或访问http://www.odata.org)。

  通过引入一组广泛的、公认的分隔符,用于过滤的表明式可以以尤其直观的款式被利用。用那几个分隔符来设置过滤查询参数的值,那么些分隔符所创立的参数名/值对可以越来越不难地被服务端解析并压实多少查询的特性。如今已部分分隔符包含用来分隔每个过滤短语的竖线(”|”)和用来分隔参数名和值的双冒号(”::”)。那套分隔符充裕唯一,并符合大多数动静,同时用它来创设的字符串查询参数也越发不难了然。下边将用一个简易的例证来介绍它的用法。借使大家想要给名为“托德”的用户们发送请求,他们住在明尼阿波利斯,有着“Grand
Poobah”之称。用字符串查询参数完毕的央浼URI如下:

  GET
http://www.example.com/users?filter="name::todd|city::denver|title::grand
poobah”

  双冒号(”::”)分隔符将属性名和值分开,那样属性值就可见包罗空格——服务端能更易于地从属性值中分析出分隔符。

  注意查询参数名/值对中的属性名要和服务端重返的属性名相匹配。

  简单而使得。有关大小写敏感的标题,要按照具体状况来看,但看来,在毫无关怀大小写的图景下,过滤效果可以很好地运行。若查询参数名/值对中的属性值未知,你也足以用星号(”*”)来代替。

  除了不难的表明式和通配符之外,若要举办更复杂的查询,你不能不要引入运算符。在那种景色下,运算符本身也是属性值的一有些,可以被服务端解析,而不是变成属性名的一有的。当需求复杂的query-language-style(查询语言风格)功效时,可参考Open
Data Protocol (OData) Filter System Query
Option表达中的查询概念(详见http://www.odata.org/documentation/uriconventions#FilterSystemQueryOption)。

排序

  排序决定了从服务端再次来到的记录的次第。也就是对响应中的多条记下举办排序。

  同样,大家那边只考虑部分比较简单的景观。推荐使用排序字符串查询参数,它富含了一组用分隔符分隔的属性名。具体做法是,默许对各种属性名按升序排列,如若属性名有前缀”-“,则按降序排列。用竖线(”|”)分隔每个属性名,那和眼前过滤效果中的参数名/值对的做法无异于。

  举个例证,要是我们想按用户的姓和名进行升序排序,而对雇佣时间展开降序排序,请求将是这样的:

  GET
http://www.example.com/users?sort=last\_name|first\_name|-hire\_date

  再度强调一下,查询参数名/值对中的属性名要和服务端重返的品质名相匹配。别的,由于排序操作比较复杂,大家只对须求的资源提供排序作用。即使必要的话也得以在客户端对小的资源聚集进行排列。

 

服务版本管理

   坦率地讲,一说到版本就会令人觉着很不便,很劳累,不太不难,甚至会令人认为愁肠——因为那会增添API的复杂度,并还要可能会对客户端爆发部分影响。由此,在API的筹划中要尽量幸免多少个不等的本子。

  不协助版本,不将版本控制作为不佳的API设计的依靠。要是你在APIs的规划中引入版本,那迟早都会让你抓狂。由于再次来到的数额通过JSON来显现,客户端会由于不一致的本子而接受到分歧的质量。那样就会设有有的题目,如从内容我和认证规则方面改变了一个已存在的特性的意义。

  当然,大家鞭长莫及幸免API可能在好哪天候要求改变重临数据的格式和情节,而那也将导致消费端的片段浮动,大家应该幸免举办一些生死攸关的调整。将API举办版本化管理是防止那种紧要变动的一种有效格局。

透过内容协商接济版本管理

  以往,版本管理通过URI本身的版本号来成功,客户端在伸手的URI中标明要获取的资源的版本号。事实上,许多大商家如推文(Tweet)、Yammer、Facebook、谷歌(Google)等不时在她们的URI里使用版本号。甚至像WSO2那样的API管理工具也会在它的URLs中要求版本号。

  面向REST原则,版本管理技术火速发展。因为它不分包HTTP规范中放置的header,也不辅助仅当一个新的资源或概念被引入时才应该添加新URI的视角——即版本不是表现方式的转移。另一个反对的理由是资源URI是不会随时间改变的,资源就是资源。

  URI应该能大约地识别资源——而不是它的“形状”(状态)。另一个就是必须指定响应的格式(表征)。还有部分HTTP
headers:Accept 和 Content-Type。Accept
header允许客户端指定所期待或能支撑的响应的传媒类型(一种或八种)。Content-Type
header可分别被客户端和劳动端用来指定请求或响应的多寡格式。

  例如,要收获一个user的JSON格式的数码:

  #Request:

  GET http://api.example.com/users/12345
  Accept: application/json; version=1

  #Response:

  HTTP/1.1 200 OK
  Content-Type: application/json; version=1

  {“id”:”12345″, “name”:”Joe DiMaggio”}

  现在,大家对同样资源请求版本2的多寡:

  #Request:

  GET http://api.example.com/users/12345
  Accept: application/json; version=2

  #Response:

  HTTP/1.1 200 OK
  Content-Type: application/json; version=2

  {“id”:”12345″, “firstName”:”Joe”, “lastName”:”DiMaggio”}

  Accept
header被用来表示所期望的响应格式(以及示例中的版本号),注意上述多个一律的URI是什么样已毕在不一样的本子中分辨资源的。或者,如若客户端要求一个XML格式的数据,可以将Accept
header设置为”application/xml”,若是必要的话也足以带一个指定的版本号。

  由于Accept
header可以被装置为允许种种媒体类型,在响应请求时,服务器将把响应的Content-Type
header设置为最匹配客户端请求内容的体系。越来越多音信方可参照http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.Html

  例如:

  #Request

  GET http://api.example.com/users/12345

  Accept: application/json; version=1, application/xml; version=1

  上述呼吁中,假诺服务器支持JSON
和XML格式的央求,或者两种都帮忙,那么将由服务器来决定最后回到哪个种类档次的数目。但不管服务器选用哪种,都会在响应中蕴藏Content-Type
header。

  例如,如若服务器再次回到application/xml格式的数据,结果是:

  #Response

  HTTP/1.1 200 OK
  Content-Type: application/xml; version=1

  <user>
    <id>12345</id>
    <name>Joe DiMaggio</name>
  </user>

  为了印证Content-Type在发送数据给服务器时的用处,这里给出一个用JSON格式创设新用户的例证:

  #Request

  POST http://api.example.com/users
  Content-Type: application/json;version=1

  {“name”:”Marco Polo”}

  或者,调用版本2的接口:

  #Request

  POST http://api.example.com/users
  Content-Type: application/json;version=2

  {“firstName”:”Marco”, “lastName”:”Polo”}

当没有点名版本时,重回什么版本?

  并不必要在每一个呼吁中都指定版本号。由于HTTP
content-negotiation(内容协商)听从类型的“最佳匹配”格局,所以你的API也应有依照那或多或少。依照这一尺度,当客户端从未点名版本时,API应当重临所帮忙的最早版本。

  照旧那几个事例,获取一个user的JSON格式的数据:

  #Request

  GET http://api.example.com/users/12345
  Accept: application/json

  #Response

  HTTP/1.1 200 OK
  Content-Type: application/json; version=1

  {“id”:”12345″, “name”:”Joe DiMaggio”}

  相应地,当以POST格局向服务器发送数据时,如若服务器协理三个不等版本,而请求时又从不点名版本,和方面的事例一样——服务器会将小小/最早版本的数目包罗在body中。为了举办求证,上面的例证以JSON格式请求一个包蕴多版本资源的服务器,来创设一个新用户(预期会重回版本1):

  #Request

  POST http://api.example.com/users
  Content-Type: application/json

  {“name”:”Marco Polo”}

  #Response

  HTTP/1.1 201 OK
  Content-Type: application/json; version=1
  Location: http://api.example.com/users/12345

  {“id”:”12345″, “name”:”Marco Polo”}

伸手不扶助的版本

  当呼吁一个不协理的版本号时(包罗在API生命周期中曾经没有的资源版本),API应当再次回到一个荒唐的HTTP状态码406(表示不被接受)。其余,API还应该重回一个饱含Content-Type:
application/json的响应体,其中蕴藏一个JSON数组,用于表明该服务器匡助的品种。

  #Request

  GET http://api.example.com/users/12345
  Content-Type: application/json; version=999

  #Response

  HTTP/1.1 406 NOT ACCEPTABLE 

  Content-Type: application/json

  [“application/json; version=1”, “application/json; version=2”,
“application/xml; version=1”, “application/xml; version=2”]

怎么时候理应创造一个新本子?

  API开发中的很多地点都会打破约定,并最后对客户端暴发部分不良影响。倘若你不确定API的修改会带来什么样的结局,保障起见最好考虑动用版本控制。当你在设想提供一个新本子是不是适用时,或者考虑对现有的回到表征进行修改是不是必然能满意急需并被客户端所接受时,有如此多少个要素要考虑。

破坏性的改动

  • 变动属性名(例如将”name”改成”firstName”)
  • 删去属性
  • 变更属性的数据类型(例如将numeric变为string,
    boolean变为bit/numeric,string 变为 datetime等等)
  • 更改验证规则
  • 在Atom样式的链接中,修改”rel”的值
  • 在存活的工作流中引入必要资源
  • 变更资源的概念/意图;概念/意图或资源情状的意义不一致于它原有的意思。例如:
    • 一个content
      type是text/html的资源,此前表示的是独具扶助的传媒类型的一个”links”集合,而新的text/html则表示的是用户输入的“web浏览器表单”。
    • 一个饱含”end提姆e”参数的API,对资源”…/users/{id}/exams/{id}”表明的意思是学生在丰盛时刻付诸试卷,而新的意思则是试验的预订完结时间。
  • 透过抬高新的字段来改变现有的资源。将多少个资源集合为一个并弃用原来的资源。
    • 有如此五个资源”…/users/{id}/dropboxBaskets/{id}/messages/{id}”和”…/users/{id}/dropboxBaskets/{id}/messages/{id}/readStatus”。新要求是把readStatus资源的习性放到单独的message资源中,并弃用readStatus资源。那将导致messages资源中指向readStatus资源的链接被移除。

  纵然上边列出的并不完善,但它交给了一些会对客户端暴发破坏性影响的成形类型,那时急需考虑提供一个新资源或新本子。

非破坏性的修改

  • 在再次来到的JSON中添加新属性
  • 丰硕指向任何资源的”link”
  • 添加content-type接济的新格式
  • 添加content-language协助的新格式
  • 是因为API的创小编和消费者都要拍卖分裂的casing,由此casing的成形无关首要

版本控制应在什么级别出现?

  提议对单个的资源进行版本控制。对API的局地变更,如修改工作流,也许要跨五个资源的版本控制,以此来防患对客户端爆发破坏性的影响。

选用Content-Location来增强响应

  可选。见RDF(Resource Description Framework,即资源描述框架)规范。

带有Content-Type的链接

  Atom风格的链接协助”type”属性。提供丰富的信息以便客户端可以对一定的本子和情节类型进行调用。

找出援救的版本

本身应该而且援助多少个版本?

  维护多少个不等的版本会让工作变得繁琐、复杂、简单出错,而且代价高,对于其它给定的资源,你应当接济不超越2个版本。

弃用

  Deprecated(弃用)的目标是用来证实资源对API仍旧可用,但在前些天会不设有并变得不可用。专注:弃用的时长将由弃用政策决定——那里并不曾交到定义。

自我何以告知客户端被弃用的资源?

  许多客户端未来作客的资源可能在新本子引入后会被甩掉掉,由此,他们须要有一种情势来发现和督察他们的应用程序对弃用资源的运用。当呼吁一个弃用资源时,API应该健康响应,并涵盖一个布尔类型的自定义Header
“Deprecated”。以下用一个例子来拓展表达。

  #Request

  GET http://api.example.com/users/12345
  Accept: application/json
  Content-Type: application/json; version=1

  #Response

  HTTP/1.1 200 OK
  Content-Type: application/json; version=1
  Deprecated: true
  {“id”:”12345”, “name”:”Joe DiMaggio”}

 

日子/时间拍卖

  如若没有妥善地、一致地处理好日期和岁月以来,那将变为一个大麻烦。我们平常会遇上时区的标题,而且由于日期在JSON中是以字符串的格式存在的,即使未指定统一的格式,那么解析日期也会是一个难题。

  在接口内部,服务端应该以UTC或GMT时间来储存、处理和缓存时间戳。那将使得化解日期和岁月的难题。

Body内容中的日期/时间连串化

  有一个简单的格局可以化解这么些标题——在字符串中一向用相同的格式,包罗时间片(带有时区消息)。ISO8601时间格式是一个科学的缓解方案,它使用了完全增强的时光格式,包含时辰、分钟、秒以及秒的小数部分(例如yyyy-MM-dd’T’HH:mm:ss.SSS’Z’)。指出在REST服务的body内容中(请求和响应均蕴涵)使用ISO8601代表享有的日期格式。

  顺便提一下,对于那一个基于JAVA的服务以来,DateAdapterJ库使用DateAdapter,Iso8601提姆epointAdapter和HttpHeader提姆estampAdapter类可以非常简单地解析和格式化ISO8601日期和岁月,以及HTTP
1.1
header(RFC1123)格式。可以从https://github.com/tfredrich/DateAdapterJ下载。

  对于那多少个创制基于浏览器的用户界面来说,ECMAScript5业内一开端就包蕴了JavaScript解析和创设ISO8601日期的情节,所以它应当成为大家所说的主流浏览器所遵守的方式。当然,若是您要辅助这个不可以自动解析日期的旧版浏览器,可以动用JavaStript库或正则表达式。那里有多少个可以分析和开创ISO8601时间的JavaStript库:

  http://momentjs.com/

  http://www.datejs.com/

HTTP Headers中的日期/时间体系化

  但是上述提议仅适用于HTTP请求或响应内容中的JSON和XML内容,HTTP规范针对HTTP
headers使用另一种差其余格式。在被RFC1123更替的RFC822中提出,该格式包蕴了种种日期、时间和date-time格式。但是,提出始终使用时间戳格式,在你的request
headers中它看起来像这么:

  Sun, 06 Nov 1994 08:49:37 GMT

  不过,那种格式没有考虑微秒或者秒的十进制小数。Java的SimpleDataFormat的格式串是:”EEE,
dd MMM yyyy HH:mm:ss ‘GMT'”。

 

保险服务的平安

  Authentication(身份认证)指的是肯定给定的伸手是从服务已知的某人(或某个系统)发出的,且请求者是她自己所声明的不得了人。Authentication是为着申明请求者的实际身份,而authorization(授权)是为了证实请求者有权力去履行被呼吁的操作。

  本质上,这一个历程是那般的:

  1. 客户端发起一个伸手,将authentication的token(身份注解令牌)包括在X-Authentication
    header中,或者将token叠加在伸手的查询串参数中。
  2. 服务器对authorization
    token(授权令牌)举办检查,并展开求证(有效且未过期),并基于令牌内容分析或者加载认证中央。
  3. 服务器调用授权服务,提供验证中心、被呼吁资源和须求的操作许可。
  4. 一旦授权通过了,服务器将会一连健康运行。

  上面第三步的付出可能会相比较大,然而借使就算存在一个可缓存的权位控制列表(ACL),那么在爆发远程请求前,可以在本地创建一个授权客户端来缓存最新的ACLs。

身份验证

  如今最好的做法是使用OAuth身份验证。强烈推荐OAuth2,可是它依旧居于草案景况。或者接纳OAuth1,它完全可以胜任。在某些景况下也可以挑选3-Legged
OAuth。更加多关于OAuth的科班可以查阅这里http://oauth.net/documentation/spec/

  OpenID是一个附加拔取。不过提议将OpenID作为一个叠加的身份验证选项,以OAuth为主。更多关于OpenID的正统可以查看那里http://openid.net/developers/specs/

传输安全

  所有的辨证都应有利用SSL。OAuth2必要授权服务器和access
token(访问令牌)来行使TLS(安全传输层协议)。

  在HTTP和HTTPS之间切换会带来安全隐患,最好的做法是负有简报默许都利用TLS。

授权

  对劳务的授权和对此外应用程序的授权一样,没有任何分化。它依照那样一个标题:“主体是还是不是对给定的资源有请求的许可?”那里给出了简便的三项数据(主体,资源和认同),由此很不难构造一个协助那种概念的授权服务。其中焦点是被予以资源访问许可的人或系统。使用这个相似概念,就足以为每一个要旨打造一个缓存访问控制列表(ALC)。

应用程序安全

  对RESTful服务来说,开发一个康宁的web应用适用同样的原则。

  • 在服务器上证实所有输入。接受“已知”的没错的输入并驳回错误的输入。
  • 防止SQL和NoSQL注入。
  • 动用library如微软的Anti-XSS或OWASP的AntiSammy来对出口的数额开展编码。
  • 将信息的尺寸限制在规定的字段长度内。
  • 服务应该只显示一般的错误新闻。
  • 考虑工作逻辑攻击。例如,攻击者可以跳过多步骤的预定流程来预定产品而无需输入信用卡音讯吗?
  • 对疑惑的活动记录日志。

  RESTful安全需要专注的地点:

  • 表明数据的JSON和XML格式。
  • HTTP动词应该被限制在同意的措施中。例如,GET请求不可以去除一个实体。GET用来读取实体而DELETE用来删除实体。
  • 小心race
    conditions(竞争条件——由于七个或者多个进度竞争使用无法被同时做客的资源,使得那几个进度有可能因为时间上拉动的次第原由此产出难题)。

  API网关可用于监视、限制和决定对API的拜访。以下内容可由网关或RESTful服务完成。

  • 蹲点API的应用状态,并询问如何活动是健康的,哪些是非正常的。
  • 范围API的行使,使恶意用户不可能停掉一个API服务(DOS攻击),并且有能力阻止恶意的IP地址。
  • 将API密钥存储在加密的平安密钥库中。

 

缓存和可伸缩性

  通过在系统层级消除通过远程调用来得到请求的数码,缓存提升了系统的可扩张性。服务通过在响应中设置headers来升高缓存的力量。遗憾的是,HTTP
1.0中与缓存相关的headers与HTTP
1.1例外,因而服务器要同时帮忙二种版本。下表给出了GET请求要帮助缓存所不可不的最少headers集合,并交给了至极的叙述。

HTTP Header

描述

示例

Date

一呼百应重回的日期和时间(RFC1123格式)。

Date: Sun, 06 Nov 1994 08:49:37 GMT

Cache-Control

一呼百应可被缓存的最大秒数(最大age值)。即便响应不援救缓存,值为no-cache。

Cache-Control: 360

Cache-Control: no-cache

Expires

只要给出了最大age值,该时间戳(RFC1123格式)表示的是响应过期的日子,也就是Date(例如当前日期)加上最大age值。借使响应不接济缓存,该headers不设有。

Expires: Sun, 06 Nov 1994 08:49:37 GMT

Pragma

当Cache-Control为no-cache时,该header的值也被设置为no-cahche。否则,不存在。

Pragma: no-cache

Last-Modified

资源本身最终被修改的时日戳(RFC1123格式)。

Last-Modified: Sun, 06 Nov1994 08:49:37 GMT

  为了简化,那里举一个响应中的headers集合的例证。这是一个简短的对资源拓展GET请求的响应,缓存时长为一天(24时辰):

  Cache-Control: 86400
  Date: Wed, 29 Feb 2012 23:01:10 GMT
  Last-Modified: Mon, 28 Feb 2011 13:10:14 GMT
  Expires: Thu, 01 Mar 2012 23:01:10 GMT

  上面是一个接近的例子,可是缓存被统统禁用:

  Cache-Control: no-cache
  Pragma: no-cache

ETag Header

  ETag
header对于注脚缓存数据的新旧程度很有用,同时也推进条件的读取和更新操作(分别为GET和PUT)。它的值是一个任意字符串,用来表示回到数据的版本。不过,对于重返数据的例外格式,它也得以分歧——JSON格式响应的ETag与同样资源XML格式响应的ETag会分裂。ETag
header的值可以像带有格式的底层域对象的哈希表(例如Java中的Obeject.hashcode())一样简单。提议为每个GET(读)操作再次来到一个ETag
header。别的,确保用双引号包涵ETag的值,例如:

  ETag: “686897696a7c876b7e”

 

HTTP状态码(前10)

  以下是由RESTful服务或API重回的最常用的HTTP状态码,以及一些有关它们广泛用法的简便表达。别的HTTP状态码不太平日采纳,它们依旧更奇特,要么更高级。一大半劳动套件只支持那个常用的状态码,甚至只协理其中的一局地,并且它们都能正常干活。

  200 (OK) —— 经常的功成名就景象。表示成功的最普遍代码。

  201 (CREATED) ——(通过POST或PUT)创立成功。通过安装Location
header来含有一个针对性最新创制的资源的链接。

  204 (NO CONTENT)
—— 封装过的响应没有选拔,或body中向来不其他内容时(如DELETE),使用本场所。

  304 (NOT MODIFIED)
—— 用于有规范的GET调用的响应,以减小带宽的利用。
即使拔取这场合,那么必须为GET调用设置Date、Content-Location和ETag
headers。不包罗响应体。

  400 (BAD REQUEST)
—— 用于履行请求时或者引起无效状态的形似错误代码。如域名无效错误、数据丢失等。

  401 (UNAUTHORIZED)
—— 用于紧缺认证token或评释token无效的错误代码。

  403 (FORBIDDEN)
—— 未授权的用户执行操作,没有权力访问资源,或者出于某些原因资源不可用(如时间范围等),使用该错误码。

  404 (NOT FOUND)
—— 无论资源存不设有,无论是还是不是有401、403的界定,当呼吁的资源找不到时,出于安全因素考虑,服务器都能够应用该错误码来掩饰。

  409 (CONFLICT)
—— 每当执行请求可能会唤起资源争执时利用。例如,存在重新的实业,当不匡助级联删除时去除根对象。

  500 (INTERNAL SERVER ERROR)
—— 当服务器抛出非凡时,捕捉到的一般错误。

 

叠加资源

书籍

  REST API Design Rulebook,Mark Masse, 2011, O’Reilly Media, Inc.

  RESTful Web Services, Leonard Richardson and Sam Ruby, 2008,
O’Reilly Media, Inc.

*  RESTful Web Services Cookbook, Subbu Allamaraju, 2010, O’Reilly
Media, Inc.*

  REST in Practice: Hypermedia and Systems Architecture, Jim Webber,
et al., 2010, O’Reilly Media, Inc.

  APIs: A Strategy Guide, Daniel Jacobson; Greg Brail; Dan Woods,
2011, O’Reilly Media, Inc.

网站

  http://www.restapitutorial.com
http://www.toddfredrich.com

  http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  http://www.json.org/
https://github.com/tfredrich/DateAdapterJ

  http://openid.net/developers/specs/
  http://oauth.net/documentation/spec/
  http://www.json.org/JSONRequest.html
http://labs.omniti.com/labs/jsend

  http://enable-cors.org/
  http://www.odata.org/documentation/uri-conventions#FilterSystemQueryOption
  http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
  https://developer.linkedin.com/apis
  http://developers.facebook.com/docs/reference/api/
  https://dev.twitter.com/docs/api
http://momentjs.com/

  http://www.datejs.com/

 

在原翻译的底蕴上经过改动:http://blog.csdn.net/huayuqa/article/details/62237010

英文原文下载:RESTful Best Practices-v1
2.pdf

Leave a Comment.