美学原理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架构方式讲述了六种植设计则。这些用于架构的规划则,最早是出于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