前言
“大多数软件系统在创建时都有一个隐含的假设:整个系统处在一个实体的控制之下;或者至少参与到系统中的所有实体都向着一个共同目标行动,而不是有着各自不同的目标。当系统在互联网上开放地运行时,无法**地满足这样的假设。”
——Roy Fielding
Architectural Styles and the Design of Network-based Software Architectures“ Discordia 信徒应该一直使用官方的Discordian 文档编号系统。”
—— Malaclypse the Younger 和 Lord Omar Khayyam Ravenhurst
我要向你展示一种可以更好地进行分布式计算的方式,它使用了有史以来*成功的分布式系统,即万维网的根本思想。如果你已经决定(或者你的经理已经决定)需要为你的公司发布一个web API 的话,我希望你能够读一下这本书。不管在你计划中的是一个公共的API,还是一个纯粹的内部API,抑或是一个只有受信伙伴可以访问的API——它们都可以从REST 的哲学中受益。
如果你想学习如何编写API 客户端的话,那么这本书对你来说并不是必要的。这是因为大多数现有的API 设计都基于一些有着数年之久的假设,而这些假设正是我想要摧毁的。
大部分今天的API 都有着一个很大的问题:一旦部署,它们将无法改变。有一些大名鼎鼎的API 会在一次部署后多年保持静态不变,即使围绕它们的行业发生着改变,这是因为要改变它们非常困难。
但是RESTful 架构是为掌控变化而设计的。万维网由数百万的网站组成,运行在数千种不同的服务器实现之上,并且经历着周期性的重新设计。这些网站被数十亿的用户访问着,而这些用户使用着几十种硬件平台之上的数百种不同的客户端实现。你的部署在一开始可能看上去不会如此混乱,但是当你的应用越发接近web 的规模时,你将会看到越发相似的混乱景象。
要改变一个非常简单的系统通常都是很容易的。在规模很小时,一个RESTful 系统比一个一键式的解决方案(push-button solution)需要花费更多预支的设计成本。但是当你的API 逐渐成熟并开始发生变化时,你将会真正需要一些像REST 这样的方式来应对变化。
y 一个商业上成功的API 将保持连续多年的可用。一些API 拥有数百甚至是数以千计的用户。就算问题域只是偶然地发生变化,对客户端带来的累积效应将是非常大的。
y 有一些API 一直都在发生变化,新的数据元素和业务规则不断地被添加进来。
y 在某些API 中,每个客户端都可以通过改变工作流来使其适合自己的需求。即使API 自身从不变化,每个客户端对API 的经历(鉴于经历不同的工作流)将会不同。
y ���写API 客户端的人通常不会和编写服务器的人隶属于同一个团队。所有向公共开放的API 都属于这一类。
如果你不知道外部的客户端是哪种类型的话,你需要在做出变化时格外小心——否则你就需要一个能够在发生变化时保证不会破坏所有客户端的设计。如果你为你的API 复制了现有的设计,你将很可能只是在重复以往犯过的错误。不幸的是,大部分的改进发生在幕后,它们大都还处于实验阶段并需要经过漫长的标准流程。我将会在本书中讨论到数十种特定的技术,包括很多还仍然处于开发之中。但是我的主要目标是要教会你REST 的基本原则。通过对这些内容的学习,你将可以对任何实验成果以及那些通过流程审核的标准善加利用。
这里有两个我想在本书中尝试解决的具体问题:重复的工作以及对超媒体的逃避。让我们来看看它们。
重复的工作
现今已发布的API 都是根据托管它们的公司的名字进行命名的。我们谈论着“Twitter API”、“Facebook API”和“Google+ API”。这三套API 做着相似的事情。它们都拥一些用户账户的概念,(在其他方面)它们都允许用户向自己的账户发布文本信息。但是每个API 都具有完全不同的设计,学习一个API 并不能帮助你学习下一个。当然,Twitter、Facebook 和Google 都是互相竞争的大型公司,它们并不想让你很容易地就学会它们竞争对手的API。但是小公司和非营利性组织也在做着相同的事。它们重新设计着自己的API,就好比从来没有人在这方面有过相似的想法一样,但是这干扰了它们想让人们实际使用它们的API 的目标。
让我来向你展示一个例子吧。网站ProgrammableWeb(http://www.programmableweb.com/)拥有着一个超过8000 个API 的目录。当我正在编写此书之时,它已经收录了57种微博API——这些API 的主要用途是向用户的账户发布文本信息注2。很不错,有57 家公司在这个领域发布了API,但是我们真的需要57 种不同的设计吗?我们在这里讨论并不是那些复杂难懂的业务,例如保险政策或法规守则,我们讨论的只是向用户账号发布少量的文本信息。你想成为那个设计第58 种微博API 的人吗?
*显而易见的解决方案便是创建一个微博API 的标准。但是我们已经有了一个可以很好工作的标准:Atom 发布协议(Atom Publishing Protocol)。它发布于2005 年,然而几乎没有人使用它。有一些关于API 的原因,使得每个人都想从头开始设计他们自己的API,即使从业务的角度来看这并没有什么意义。
我不认为凭我一个人的力量就能结束这种无用功,但是我确实认为可以将问题分解成若干有意义的小块,然后提供一些方式来让新的API 可以复用已经完成的这些工作。
超媒体很难
早在2007 年,Leonard Richardson 和Sam Ruby 编写了本书的前身,RESTful Web Services(O'Reilly)。那本书同样也尝试于解决两个大的问题。其中一个问题已经被解决,而另一个却没有任何进展。
**个问题是:在2007 年,在API 设计的多个阵营中,REST 学派正在与使用基于SOAP 等重量级技术的对手学派进行对峙,他们忙于应对来自对方的对REST 学派合理性的质疑。RESTful Web Services 一书的出现打破了这种对峙的僵局,有效地为RESTful设计原则防御了来自SOAP 学派的进攻。
很好,这场对峙已经结束,而REST 赢得了胜利。SOAP API 仍在被使用着,不过**于那些起初支持SOAP 学派的大公司。几乎所有面向公众的API 口头上都说自己遵守了RESTful 原则。
这又将我们带到了第二个问题:REST 并不只是一个技术词汇——它同样还是一个营销术语。在很长一段时间里,REST 成了一个口号,它象征着任何站在SOAP 学派对立面的势力。任何没有使用SOAP 的API 都将自己标榜为REST,即使它的设计与REST 毫无关系甚至是违背了REST 的基本原则。这样做是错误的,是令人困惑的,它给REST这个技术词汇带来了一个坏名声。
这种情况自2007 年便有了较大的改善。每当我审视那些新的API,我看到了***们的工作,可以看得出,这些开发人员是理解那些我将在本书前几章中解释的概念的。今天大部分举着REST 大旗的***都理解资源和表述,理解如何使用URL 来为资源命名,以及如何正确地使用HTTP 方法。因此本书的前三章将不需要做过多的事情,只需让新的***加速赶上我们即可。
但是在REST 中,还有一个方面令大部分的开发人员仍然无法理解,即:超媒体。我们都理解Web 环境中的超媒体。它只是作为代表链接的一个华丽的词汇。网页经过互相的链接,随即产生了万维网,万维网便是由超媒体驱动的。但是,貌似只要在web API中涉及到超媒体,我们便有了心理障碍。这是一个大问题,因为超媒体是一项能让web API 优雅处理变化的特性。
从RESTful Web APIs 一书的第4章开始,我的首要目标便是教会你超媒体的工作原理。如果你从未听到过这个词,我将会结合其他重要的REST 概念向你讲授该词。如果你听到过超媒体,但是这个概念吓到了你,我将会尽我所能来为你建立勇气。如果你无法将超媒体装进你的大脑,我将会以各种我所能想到的方式来向你展示超媒体,直到你记住并理解它。
RESTful Web Services 一书也涉及到了超媒体,但是这并不是该书的**所在。就算跳过该书的超媒体部分也可以照样设计出一个功能性的API。相比之下,RESTful Web APIs则是一本真正有关超媒体的书。
我之所以这样做是因为超媒体是REST *重要的一个方面,也是*不被理解的一个方面。在我们完全理解超媒体之前,REST 将会被继续视为一个营销术语,而不是对处理分布式计算复杂性的一次认真的尝试。
这本书讲了什么?
前4个章节介绍了REST 背后的概念,并将其应用于web API。
第1章,网上冲浪
这一章通过一个你已经熟悉的RESTful 系统:网站,来对基本的术语进行了说明。
第2章,一个简单的API
这一章将我们在Web 上的经验转换到了一个可编程API 中,该API 与第1章中所讨论的网站具有相同功能。
第3章,资源和表述
资源是HTTP 中的基本概念,而表述则是REST 中的基本概念。本章对它们之间是如何进行关联的进行了说明。
第4章,超媒体
超媒体是一种缺失的材料,可以将它和表述一起整合进一个一致的API。本章展示了超媒体可以做些什么,并大都使用了你已经熟悉的超媒体数据格式:HTML。
接下去的4个章节描述了用于设计超媒体API 的不同策略:
第5章,领域特定设计
显而易见的一个策略是设计一个全新的标准来处理你的具体问题。我使用了Maze+XML 标准来举例说明。
第6章,集合模式(Collection Pattern)
很特别的一个模式:集合模式,在API 设计中出现了一次又一次。在这一章中,我展示了两个不同的标准:Collection+JSON 和AtomPub,它们都实现了这种模式。
第7章,纯- 超媒体设计
当集合模式无法满足你的需求时,你可以使用一种通用的超媒体格式来传达任意的表述。这一章使用了3 种通用超媒体格式(HTML、HAL 和Siren)作为实例来展示上述方式是如何工作的。这一章同样还介绍了HTML 微格式和微数据,并以此引出了下一章的内容。
第8章,Profile
Profile 可以用于填平某种数据格式(可以被多种不同的API 使用)与某个特定API实现之间的鸿沟。我所**的profile 格式是ALPS,但是我同样也提到了XMDP和JSON-LD。
在这一章中,我给出的建议开始超越了编写本书时的艺术状态(outstrip the state of the art)。因此我不得不为本书开发了ALPS 格式,因为当时还没有其他可以完成这项工作的选择。如果你已经对基于超媒体的设计非常熟悉,那么你可以跳过前面的部分直接来到第8 章,但是我不认为你应该跳过第8 章。
第9 章到第13 章涉及到了例如选择正确的超媒体格式以及如何充分利用HTTP 协议这些实用主题。
第9章,API 设计流程
这一章将本书到目前为止讨论过的所有内容整合在了一起,并给出了一个用于设计RESTful API 的按部就班的指引。
第10 章,超媒体动物园
为了展示超媒体的能力,本章讨论了近20 种标准化的超媒体数据格式,它们中的大部分并没有在本书的其他章节中有所涉及。
第11 章,API 中的HTTP
本章给出了在API 实现中使用HTTP 的一些*佳实践。我同样也讨论了一些HTTP的扩展,包括即将到来的HTTP 2.0 协议。
第12 章,资源描述和Linked Data
Linked Data 是语义网社区用以实现REST 的方法。JSON-LD 毫无疑问是*重要的Linked Data 标准。我们曾在第8 章谈到过它,而我在本章中对它进行了重温。本章同样讨论了RDF 数据模型和一些我在第10 章没能谈到的基于RDF 的超媒体格式。
第13 章,CoAP: 嵌入式系统的REST
本章通过对CoAP 的讨论结束了本书的核心部分,CoAP 是一个完全没有使用HTTP 的RESTful 协议。
附录A,状态法典
作为对第11 章的扩展,本附录对HTTP 规范中定义的41 个标准状态码以及一些作为扩展定义的有用的状态码进行了深入的考察。
附录B,HTTP 报头法典
与附录A 相似,本附录也是对第11 章的扩展。它为HTTP 规范中定义的46 个请求和响应报头,以及一些扩展提供了详细的概述。
附录C,为API 设计者准备的Fielding 论文导读
本附录包括了一个围绕REST 的基础文档(即Fielding 论文)展开的深度讨论,用以说明该文档在API 设计中的意义。
词汇表
该词汇表包含了你在RESTful Web APIs 一书中会经常遇到的一些术语的定义。如果你想要熟悉基本概念,或者是需要一个快速的、用于浏览特定概念定义的提示工具,那么这将是一个很好的去处。
这本书没讲什么
RESTful Web Services 是*早有关REST 的一部书籍,并且涉及了很多的背景知识。幸运的是,现在已经有着超过一打的关于REST 的各个方面的书,而这样便让RESTful Web APIs 可以腾出精力来专注于核心的概念。
为了保持本书的专注度,我去除了部分你可能会希望我覆盖到的主题。我想要告诉你这本书没讲什么,这样你便可以选择不购买本书,从而不会为此感到失望:
y 本书没有涉及到客户端编程。编写客户端来消费基于超媒体的API 是一种新的挑战。眼下,对一个通用的API 客户端来说,我们可以拥有的就是一个能够发送HTTP 请求的代码库。这在2007 年如此,时至**仍然如此。因为问题存在于服务器端。当你要为一个现有的API 编写客户端时,你将只能仰仗API 设计者。我无法给你任何通用的建议,因为现在并不存在跨API 的一致性。这就是为什么我在本书中鼓动大家保持对服务器端一致性的积极性的原因。当API 之间变得更加相似,我们也就可以编写更为精细的客户端工具。
第5 章包含了一些示例的客户端实现,并尝试对不同类型的客户端进行归类,但是如果你想要一本全部关于API 客户端的书,那么这本书并不适合你。我不认为目前市场上存在着你想要的书。
y 世界上部署*广泛的API 客户端应当属JavaScript 的XMLHttpRequest 代码库。在每一个浏览器中都拥有一份该代码的副本,而当今大部分的网站也都构建于那些专门设计供XMLHttpRequest 消费的API 之上。对于本书来讲,这个领域过于庞大而无法完全涉及。市场上有着全篇专门讲述JavaScript 代码库的书籍。
y 我花费了相当多的时间来讨论HTTP 的机制(第11 章、附录A 和附录B),但是我没有覆盖到任何具有深度的特定HTTP 主题,有一些主题,尤其是关于缓存和代理这样的HTTP 中间组件的相关主题,我只是简单地在本书中有所涉及。
y RESTful Web Services **专注于将你的业务需求拆分成一组互相关联的资源。根据我2007 年以来的经验,我深信将API 设计作为一种资源设计来思考可以有效地避免考虑超媒体。但本书却采用了一种截然不同的方式,它专注于表述和状态转换,而非资源。
也就是说,资源设计的方式无疑也是有效的。如果想听听在该方向发展的建议,我**由Subbu Allamaraju 编著的RESTful Web Services Cookbook(O’Reilly)。
管理备注
本书有两名作者(Leonard 和Mike),但是在编写本书的过程中,我们被合并成了一个**人称,即“我”。
本书中的内容没有与任何特定的编程语言绑定。所有的代码都采用了在网络协议(通常是HTTP)中发送的消息格式(通常是JSON 或XML 文档)。我将假定你已经熟悉了常规的编程概念,比如反模式和广度优先搜索,以及你对万维网是如何工作的有着一个基本的理解。
我将不会呈现真实的代码,但是我在第1 章、第2 章以及第5 章中所讨论的服务器和客户端背后的真实代码是存在的。你可以通过RESTful Web APIs 一书的GitHub 仓库(https://github.com/organizations/RESTful-Web-APIs),或者是通过官方的网站(http://www.restfulwebapis.org/)来获取这些代码,从而可以自行将它运行起来。这些客户端和服务器是采用JavaScript 编写的,使用的是Node 代码库。
我之所以选择Node 是因为它让我可以使用相同的编程语言来编写客户端及服务端的代码。你无须为了理解某个客户- 服务器事务的两端而需要费神地在两种编程语言之间来回切换。Node 是开源的,并且可以运行在Windows、Mac 和Linux 系统上。它很容易在这些操作系统上进行安装,而你应该无须碰触太多的麻烦就可以获取这些例子,并将它们运行起来。
我将这些代码托管在GitHub 上,因为随着时间的变化,我可以非常容易地更新这些实现。这同样也使得读者们可以为这些示例的客户端和服务器贡献其他编程语言的移植版本。
理解标准
万维网并不是一个供科学研究的客观事物。它是一种社会建构(social construct)——一组按特定方式做事的协议。幸运的是,它与其他的社会建构不同(比如礼节),Web 底层的协议通常是已经约定好的。人类的web 底层*核心的协议就是RFC 2616(HTTP 标准)、HTML4 的W3C 规范以及ECMA-262(JavaScript 的基础标准,也被称为ECMAScript)。每个标准都做了不同的工作,在本书的课程中,我还将讨论数十个专门设计供API 使用的其他标准。
这些标准的伟大之处在于它们给了你坚实的基础。你可以使用它们来构建一种全新的网站或API,即某些没有人曾经尝试过的东西。并且无须向你的所有用户进行对整个系统的说明,你将只需要对那些新的部分进行说明即可。
而坏消息便是这些协议通常晦涩难读:采用拗口而**的英文编写而成的、由ASCII 文本组成的冗长的段落,像“should”这样的日常词汇也具有了技术含义,并被标准化为大写的“SHOULD”注5。市场上大量的技术书籍之所以热卖,便是因为很多人希望通过阅读书籍而避免直接阅读这样的标准文档。
好吧,我无法做出任何的担保。如果这些标准中的任何一个貌似会成为某个你可以在工作中采纳的选择,那么你必须愿意深入其规范并真正地去理解它(或者买一本能详细覆盖它的书籍)。对于像Siren、CoAP 和Hydra 这样的标准,我没有空间来为它们提供除基本概览之外的更多详情。更不用说一旦��出了太多的细节,将会让所有在工作中不需要这些特定标准的读者对此产生厌倦。
当你穿梭于标准的森林之中时,请记住一点,并不是所有的标准都具有相同的力量。有些标准制定得非常完善,每个人都在使用,如果你违背了这些标准,那么将会为你带来大量的麻烦。而其他的标准只是某些人的一家之言,而他们想法也未必比你自己的想法更加高明。
我认为将标准划归到4 个分类中将会很有帮助:fiat 标准、个人标准、公司标准以及开放标准。我将在本书中一直使用这些词,所以让我来逐个对它们进行深入的解释。
Fiat 标准
Fiat 标准并不是真正的标准;它们是一些行为。没有人认同它们。它们只是对某些人做事方式的一种描述。这些行为可以用文档记录下来,但是它缺少了作为标准的一个前提——其他人应该以相同的方式做事。
几乎当今的每个API 都是一种fiat 标准,即某种与特定公司相关联的一次性设计。这就是我们谈论着“Twitter API” 、“ Facebook API”以及“Google+ API”的原因。你可能需要通过理解这些设计来做好你的工作,并且可能要为这些设计编写你自己的客户端,除非你服务的便是我们讨论中的这家公司。请别指望在你自己的API 中使用这样的设计。
如果你复用了一个fiat 标准,我们不会说你的API 符合某个标准,我们只会认为它是一种复制。
我在本书中尝试解决的一个主要的问题便是设计工作中数以百计的人年(person-year)都被束缚在制定fiat 标准这种无法复用的工作中。必须要结束这样的事情。如今设计一个新的API 意味着重新发明一长串轮子。一旦你的API 完成了,你的客户端开发人员必须在客户端一侧对应地重新发明一串轮子。
即便在理想的情况下,你的API 仍将是一个fiat 标准,因为你的业务需求将会与其他人的需求有所不同。但是从观念上来说,一个fiat 标准将只是一束掩盖了若干其他标准的强光。
当我在描述一个fiat 标准时,我将会链接到它的人类可读的文档。
个人标准
个人标准是一种标准(你将被邀请阅读文档,并自行实现该标准),但是它们只是一个人的意见。我在第5 章中描述的Maze+XML 标准便是一个很好的例子。别指望Maze+XML 是用来实现迷宫游戏API 的标准方式,但是如果它能为你工作,你便可以很好地使用它。某些其他的人已经帮你完成了设计工作。
个人标准相对于别的标准,通常会采用较为不够正式的语言。很多开放标准开始是作为个人标准起步的——在经历了大量的实验后,作为编外项目被扶正。我在第7 章中谈到Siren 就是一个很好的例子。
当我在描述一个个人标准时,我将会链接到它的规范。
公司标准
公司标准是由企业集团为了尝试解决某个困扰着它们的问题而共同创建的标准,或者是由一个单一的公司试图代表其客户解决某个反复出现的问题而制定的。公司标准相比于个人标准往往定义得更加完善,所使用的语言也更加规范,但是它们并没有比个人标准具有更大的力量。它们只是某个公司(或某个企业集团)的意见。
公司标准包括了活动流(Activity Streams)和schema.org 的元数据模式,这两项都在第10 章有所涉及。很多的行业标准都是以公司标准的形式发起的。OData(同样在第10 章中讨论过)*初以微软项目的形式启动,但是在2012 年被提交到了OASIS,并*终成为了一项OASIS 标准。
当我在描述一个公司标准的时候,我将会链接到它的规范。
开放标准
一项开放标准将会历经一个由委员会发起的设计过程,或者至少拥有一个开放的评论期,在此期间,大量的人员会阅读规范,对它提出意见,并提供改进的建议。在这个过程的*后,该规范将得到某些公认的标准组织的祝福。
该过程给开放标准带来了一定的道德力量。如果一个开放标准的内容或多或少正是你想要的,你真应该使用它来替代制定自有的fiat 标准。开放标准在设计过程和评论期间可能会暴露出大量的问题,这样一来你在实际的使用中将不大会遇到太多的问题。
一般来说,伴随着开放标准还会有很多的协议,这些协议会对你做出承诺,即当你在实现了这些开放标准之后不会受到那些参与了该标准过程的公司的专利侵权诉讼。相比之下,实现别人的fiat 标准有可能会激起他们对你的专利侵权诉讼。
本书中提到的一些开放标准大都出自那些大名鼎鼎的标准组织:ANSI、ECMA、ISO、OASIS,尤其是W3C。我无法描述在成为这些标准组织的一员后将可以怎么样,因为我从未这样做过。但是大部分重要的标准组织注6 中的任何一个都可以向IETF 做出贡献,该组织管理着所有重要的RFC。
RFCs(Requests for Comments) 和互联网草案
大部分的RFC 都是通过一个叫作标准追踪(Standards Track)的流程进行创建的。贯穿本书,我将会引用那些处于标准追踪不同环节的文档。我想要简明地讨论下追踪是如何运作的,这样一来你便会知道在采纳我的建议时需要多么认真。
一项RFC 的生命开始于一项互联网草案。这是一个看上去很像标准文档的文档,但是你不应该建立基于它的实现。你应该查找该规范的问题并给予反馈。
一项互联网草案具有一个固定6 个月的生命时间。在它发布的6 个月之后,该草案必须作为一项RFC 被通过,或者是由一项更新后的草案进行替代。如果以上的事情都没有发生,那么该草案就会被认为已经过期,并且不应该被应用于任何事物。另一方面,如果草案通过了审核,那么它就会立即过期并由一项RFC 来取代它。
因为具有固定的过期时间,同时也因为一项互联网草案从技术上说并不是任何类型的标准,所以在一本书中提及它们是一件非常棘手的事情。同时,API 设计是一个迅速变化的领域,多一项互联网草案可以选择总比没有好。我将在本书中提到多个互联网草案,并且假设它们在成为RFC 后不会有太大的变化。这个假设保持着良好的状态;有多个在我编写本书时提到的互联网草案,目前已经成为了RFC。如果某个特定的互联网草案*后并不成功,那么我在此只能先行道歉了。
RFC 和互联网草案都指定了代码名称。当我描述它们中的一员时,我不会链接到它的规范。我将只会提及它的代码并让你自己去查找它。举个例子,我会将HTTP/1.1 规范称为RFC 2616。我也会使用名字来指代某个互联网草案。举个例子,我将会使用“draftsnell-link-method”来指代向HTTP 添加LINK 和UNLINK 方法的提案。
当你看到它们中某个的代码名称时,你都可以通过网络搜索来找到该RFC 或互联网草案的*新版本。如果一项互联网草案在本书出版之后成为了RFC,那么该互联网草案的*终版本会链接到对应的RFC。
当我在描述一项W3C 或OASIS 标准时,我将会链接到对应的规范,因为那些规范没有给出代码名称。
本书所使用的约定
以下是本书所使用的排版约定:
斜体
表示新的术语(中文则用楷体)、URL、邮件地址、文件名称和文件扩展名。
等宽字体
用于表示程序片段,也可以用在正文中表示例如变量名或函数名等程序元素、数据库、数据类型、环境变量、语句和关键词(中文则用黑体)。
加粗的等宽字体
展示了应该由用户逐字输入的命令或其他文本。
倾斜的等宽字体
展示了应该由用户提供值或由上下文决定值来进行替换的文本。
这个图标代表小窍门、建议和说明。
这个图标代表警告信息。
使用代码示例
本书就是要帮读者完成工作的。通常,如果本书包含了代码示例,你可以在你的程序和文档中使用本书中的代码。除非你复制了大段的代码,否则你无须联系我们来取得许可。
举个例子,在编写程序时使用了本书中的数块代码是不需要经过许可的。出售或分发来自O’Reilly 图书的示例CD-ROM 是必须经过许可的。引用本书及本书中的示例代码来回答问题是不需要经过许可的。将大量的示例代码整合到你的产品文档中必须经过许可。
我们希望(但不是必须)你在使用我们的代码时标明出处。出处通常都包含书名、作者、出版社和ISBN。例如:“RESTful Web APIs by Leonard Richardson and Mike Amundsen(O’Reilly). Copyright 2013 Leonard Richardson and amund- sen.com, Inc., and Sam Ruby.978-1-449-35806-8”。
如果还有其他需要使用代码的情形需要与我们沟通, 可以随时与我们联系:
permissions@oreilly.com。
Safari? Books Online
Safari Books Online(www.safaribooksonline.com)是一家应需而变的数字图书馆。它同时以图书和视频的形式出版世界**技术和商务作家的专业作品。
Safari Books Online 是技术专家、软件开发人员、Web 设计师、商务人士和创意人士开展调研、解决问题、学习和认证培训的**手资料。
对于组织团体、政府机构和个人,Safari Books Online 提供各种产品组合和灵活的定价策略。用户可通过一个功能完备的数据库检索系统访问O’Reilly Media、Prentice Hall Professional、Addison-Wesley Professional、Microsoft Press、 Sams、Que、Peachpit Press、Focal Press、Cisco Press、John Wiley & Sons、Syngress、Morgan Kaufmann、IBM Redbooks、Packt、Adobe Press、FT Press、Apress、Manning、New Riders、McGraw-Hill、Jones & Bartlett、Course Technology 以及其他几十家出版社的上千种图书、培训视频和正式出版之前的书稿。要了解Safari Books Online 的更多信息,请访问我们的网站。
联系我们
关于本书的建议和疑问,可以与下面的出版社联系:
美国:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
中国:
北京市西城区西直门南大街2 号成铭大厦C 座807 室(100035)
奥莱利技术咨询(北京)有限公司
xxxiv | 前言
我们将关于本书的勘误表,例子以及其他信息列在本书的网页上,网页地址是:
http://www.oreilly.com/catalog/9781449358068
如果要评论本书或者咨询关于本书的技术问题,请发邮件到:
bookquestions@oreilly.com
想了解关于O’Reilly 图书、课程、会议和新闻的更多信息,请访问以下网站:
http://www.oreilly.com.cn
http://www.oreilly.com
致谢
我们欠Glenn Block 一声谢谢,他花费了无数的时间来聆听我们的想法,并编写了真实的代码来测试这些想法。我们要向Benjamin Young 和RESTFest 的所有人表示感谢,是他们同意成为我们实验的一部分,并给了我们很好的反馈和建议,即使我们有时听不大进去。我们要感谢Mike 在Layer 7 Technologies 的同事,包括Dimitri Sirota 和Matt McLarty,他们在这个项目的工作上给予了他支持和鼓励。我们要感谢Sam Ruby 和Mike Loukides,他们对于本书的前身RESTful Web Services 一书来说至关重要。我们要感谢Sumana Harihareswara, 她是Leonard 的贤内助。我们还要感谢社区,它为我们创造了良好的协作和交流REST 与API 的环境;尤其是Yahoo 的REST-Discuss、Google Groups 的API-Craft 以及LibreList 的Hypermedia group。
*后,感谢那些阅读了早期手稿并提供了必要的批评和支持的人,他们是:Carsten Bormann、Todd Brackley、Tom Christie、Timothy Haas、Jamie Hodge、 Alex James、David Jones、Markus Lanthaler、Even Maler、Mark Nottingham、Cheryl Phair、Sergey Shishkin、Brian Sletten、Mark Stafford、Stefan Tilkov、Denny Vrande?i?、Ruben Verborgh 和Andrew Wahbe。