NoSQLRESTful服务至上实践

正文主要读者

引言

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架构方式讲述了六种设计则。这些用于架构的筹划则,最早是由Roy
Fielding在外的博士论文中提出并定义了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的事例:

  • Twitter: https://dev.twitter.com/docs/api
  • Facebook: http://developers.facebook.com/docs/reference/api/
  • LinkedIn: https://developer.linkedin.com/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是什么”无异于节省被呢关系了。

  根据Roy
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。另外一个提案是由Douglas
Crockford提出的,可以查此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通常只能展现大数目集中的同样小一些数据。在数据集的增长速度不确定的情景下,限制默认返回的数据量是非常有必不可少之。以Twitter为条例,要获得有用户之推文(通过个人主页的时光轴),如果没特别指定,请求默认只见面回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

  在大部情下,这种分页方式还没有问题。但奇迹会产生这种状况,就是若回来的记录数据无法直接代表成数据汇总之行号。还有即使是发若干数据集的成形快,不断会出新的数插入到数码集中,这样必然会导致分页出现问题,一些又的多少或许会见面世在不同之页中。

  按日期排列的数据集(例如Twitter
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)。

  通过引入一组大的、公认的分隔符,用于过滤的表达式可以为生直观的形式给以。用这些分隔符来设置过滤查询参数的价,这些分隔符所创建的参数名/值对能够更容易地被服务端解析并加强多少查询的性。目前已部分分隔符包括用来分隔每个过滤短语的竖线(”|”)和用来分隔参数号称及价值的双冒号(”::”)。这套分隔符足够唯一,并符合大多数状,同时用它们来构建的字符串查询参数为尤为便于理解。下面将因此一个概括的例子来介绍其的用法。假设我们怀念要叫名也“Todd”的用户们发送请求,他们停下在丹佛,有着“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中标明要博取之资源的版本号。事实上,许多大商家只要Twitter、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浏览器表单”。
    • 一个分包”endTime”参数的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,Iso8601TimepointAdapter和HttpHeaderTimestampAdapter类可以非常容易地分析及格式化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

网站地图xml地图