一、RESTful Web 服务、介绍和动机

RESTful web 服务现在被广泛使用。RESTful 非常简单,在其他 web 服务中使用最广泛。事实上,它的简单性也是它出名的原因之一。如果您正在阅读这本书,那么您可能对 RESTfulWeb 服务有所了解。你可能用过它,或者你刚刚听说过它。但是,即使您对 RESTful web 服务了解不多,也不要担心,因为我们首先在这里定义它。首先,让我们列出本章将要讨论的高层次主题:

  • Web 服务,什么是 Web 服务?
  • REST 体系结构(REST 的约束)
  • RESTful web 服务
  • RESTful web 服务的约定
  • HTTP 动词(方法)
  • 为什么是 RESTful web 服务?
  • 响应类型和响应代码
  • 案例研究-博客的 RESTful web 服务端点

然而,对于 RESTfulWeb 服务有很多误解。例如,有些人认为通过 web 返回 JSON 的任何东西都是 RESTful web 服务,RESTful web 服务只返回 JSON。事实并非如此。

事实上,RESTful web 服务支持多种格式,并且并非所有返回 JSON 的内容都是 RESTful web 服务。为了避免混淆,让我们了解什么是 RESTfulWeb 服务。

基于 REST 体系结构的 web 服务是 RESTful web 服务。那么,什么是 web 服务和 REST 体系结构呢?让我们首先了解 web 服务,然后了解 REST 体系结构。

网络服务

Web 服务在不同的地方有不同的定义。逐字翻译表示,在 web 上提供的任何服务(包括网页)都是 web 服务,但如果提及技术术语web 服务,则不是这样。

要定义 web 服务,我们将从 W3C 词汇表中查看 web 服务定义:

"A Web service is a software system designed to support inter-operable machine-to-machine interaction over a network. It has an interface described in a machine-process able format (specifically WSDL). Other systems interact with the Web service in a manner prescribed by its description using SOAP-messages, typically conveyed using HTTP with an XML serialization in conjunction with other Web-related standards." -W3C, web services glossary.

同样,这个定义并不完全正确,因为它更具体于基于 SOAP 和 WSDL 的 web 服务。事实上,在 2004 年 2 月 11 日的 W3C 工作组说明中,有人指出:

"We can identify two major classes of web services: - REST-compliant web services, in which the primary purpose of the service is to manipulate XML representations of Web resources using a uniform set of "stateless" operations; - and arbitrary web services, in which the service may expose an arbitrary set of operations."

因此,考虑到上述 W3C web 服务词汇表定义,web 服务的更一般、更好的定义是:

"A Web service is a software system designed to support inter-operable machine-to-machine interaction over a network."

为什么选择 web 服务?

现在,我们知道了什么是 web 服务。因此,在继续 REST 之前,了解 web 服务的需求是很重要的。在哪里可以使用 web 服务?

正如刚刚定义的,web 服务是一个支持网络上机器间可操作通信的系统。它对于不同系统或设备之间的通信非常有用。在本例中,我们将使用 web 服务提供一个接口,通过该接口,移动应用程序或 web 应用程序将能够与服务器通信以获取和存储数据。这将使客户端应用程序与服务器端逻辑分离。如今,SPA(单页应用程序)和移动应用程序需要独立,与服务器端分开,并且只与服务器端逻辑和 web 服务交互。因此,毫无疑问,web 服务在当今非常重要。然而,web 服务的使用不仅限于客户端应用程序的使用,而且在一台服务器充当客户端的服务器到服务器通信中也很有用。

REST 体系结构

REST 表示代表性状态转移。这是罗伊·菲尔丁在 2000 年创立的一种建筑风格,并在他的博士论文中进行了阐述。他表示,REST提供了一组架构约束,当作为一个整体应用时,强调组件交互的可伸缩性、接口的通用性、组件的独立部署和中间组件,以减少交互延迟、加强安全性并封装遗留系统。

REST 是基于网络的应用程序的体系结构样式,HTTP1.1 就是基于它的,因为它是与 HTTP1.1 并行开发的。

RESTful 系统或 RESTful web 服务必须遵守以下六个约束:;否则,它将不会被视为 RESTful 或 REST 兼容。在阅读和理解以下提到的限制时,请将现代 web 作为 REST 体系结构的一个示例。

客户端服务器

REST 是关于分离客户机和服务器的。这个限制是关于“关注点分离”。这意味着服务器和客户端有各自的职责,因此一方不负责另一方的职责。例如,客户机不负责服务器上的数据存储,因为这是服务器的责任。同样,服务器不需要知道用户界面。因此,服务器和客户机都执行各自的任务并履行各自的职责,这使他们的工作更轻松。因此,服务器可以更具可扩展性,客户机上的用户界面可以独立且更具交互性。

无国籍

客户端-服务器通信是无状态的。来自客户的每个请求都将包含服务请求所需的所有信息。这意味着除了请求中的状态外,此通信中没有其他状态。客户端将得到的响应将基于请求,而不查看请求中的状态以外的任何状态。

如果需要维护会话,则将基于请求中的令牌或标识符来存储会话。因此,如果我们看一个 web 请求的例子,那么 HTTP 的流只不过是客户端发送给服务器的请求和服务器发送回客户端的响应,如下图所示:

如果需要维护会话,会话数据将存储在服务器上,而会话标识符将发送回客户端。在后续请求中,客户端将在每个请求中包括该会话标识符,服务器将通过该标识符识别客户端并加载相关会话的数据,如下图所示:

在随后的请求中:

所以 REST 是无状态的。要维护该状态,需要传递标识符或任何其他信息,对不同的请求进行逻辑分组,以维护请求中的会话。如果请求中没有传递这样的标识符,服务器将永远不会知道这两个请求是否来自同一个客户端。

无状态的优点是简单。相同的请求不会产生不同的响应,除非更改请求参数。它将根据不同的请求参数返回不同的结果,而不是由于某种状态。甚至状态也取决于请求,如前一示例所示。因此,会话标识符位于请求中,这可能导致不同的状态,从而导致不同的响应。

可缓存

此约束指定 RESTful web 服务响应必须将自身定义为可缓存或不可缓存,以便客户端可以知道是否应该缓存它。如果定义正确,它可以减少开销并提高性能,因为如果客户端能够使用缓存版本,它就不会转到服务器。

均匀界面

统一界面是最显著的约束。它基本上解耦了体系结构,使接口与实现分离,就像任何好的系统一样。

它与 OOP 中的情况类似:一个接口将实现和声明分开。这类似于操作系统如何将用户界面从保持软件运行的复杂实现逻辑中分离出来。

统一界面有四个约束。为了理解统一接口,我们需要理解这些约束。

资源识别

资源将在请求中确定。例如,基于 web 的 REST 系统中的资源将由 URI 标识。而且,无论资源如何存储在服务器上,它都将与响应中返回给客户机的内容保持分离。

事实上,服务器上的资源存储是一个实现,但请求和响应是客户机与之交互的对象,因此它就像是客户机的接口。客户端可以通过该接口识别资源。因此,客户所知道的就是它所请求的和得到的响应。

例如,客户机通常向 URI 发送请求,并以 HTML、JSON 或 XML 的形式获取响应。这些格式都不是服务器在数据库内部或服务器上其他地方存储数据的方式。但对于客户机来说,它将命中 URI,而 HTML、JSON 和 XML 就是它得到的。

无论资源如何存储在服务器上,这都是客户机的资源。这就是好处,因为无论服务器的内部逻辑或表示是否发生了更改,对于客户端来说,它都将保持不变,因为客户端将请求发送到 URI,并以 HTML、JSON 或 XML 的形式获得响应,而不是它在服务器上的存储方式。这种约束导致资源标识和表示的松散耦合。

通过表示操作资源

该约束规定,客户机应持有资源的表示形式,该资源具有足够的信息来修改或删除该资源。例如,在基于 web 的 REST 系统中,可以使用 HTTP 方法和 URI 对资源执行任何操作。这使得事情易于遵循,因为 API 开发人员不需要为与资源相关的每个端点提供文档。

自描述性消息

该约束规定,每个消息都应该能够根据其自身包含的信息进行处理。这意味着,服务器和客户端之间传递的每一条消息都应该是无状态的,并且独立于其他消息。一条消息对其他消息没有影响。因此,两条消息是否按特定顺序传递并不重要,因为它们是独立的。消息中的请求足以获得响应,并且该响应具有需要传达的所有信息。

作为应用程序状态引擎的超媒体(HATEOAS)

该约束表示,基于服务器向 REST 客户端提供的内容,REST 客户端应该能够发现所有可用的操作和资源。换句话说,它指出,如果客户机从第一个端点知道入口点,那么它应该能够发现与该资源相关的其他相关端点。例如,如果客户机转到资源的列表端点,则该端点应包含指向该列表中资源的链接。如果应用了分页或限制,则它应该具有指向列表中其他项的链接。

如果客户机创建了一个新资源,那么新资源的链接也应该包含在响应中,该链接可以通过使用不同的 HTTP 谓词对该资源执行读取、更新和删除操作。对于除典型 CRUD 以外的操作,它显然会有更多的 URL,因此这些操作的 URL 也应该在响应中,以便可以从一个入口点发现与资源相关的所有端点。

由于 HATEOAS,端点公开到相关端点的链接。这减少了对完整的 API 文档的需要,尽管不是完全的,但是对于已经公开的链接,不需要查看 API 文档。

按需编码(可选)

这表明服务器可以通过发送可由该客户端执行的代码,向 REST 客户端添加更多功能。在 web 环境中,服务器发送到浏览器的 JavaScript 代码就是这样一个例子。

让我们考虑一个例子来更好地理解这一点。

例如,web 浏览器的行为类似于 REST 客户端,服务器传递浏览器呈现的 HTML 内容。在服务器端,有某种服务器端语言在服务器端执行一些逻辑工作。但是,如果我们想添加一些在浏览器中工作的逻辑,那么我们(作为服务器端开发人员)必须向客户端和浏览器发送一些 JavaScript 代码,然后执行这些 JavaScript 代码。因此,JavaScript 代码可以向表单、一些动画或任何其他内容添加验证,这在 HTML 内容中是不可能的。该 JavaScript 代码是服务器发送给扩展 REST 客户端功能的客户端的按需代码。

请注意,按需向客户端发送代码是可选的,如果我们不想扩展客户端的功能,则不需要这样做。

分层系统

此约束表示 REST 系统可以有多个层,如果客户端请求响应并获得响应,则无法区分它是从服务器还是其他中间件服务器返回的。因此,如果一个服务器层被另一个服务器层替换,它不会影响客户机,除非它提供了预期的服务。简言之,一个层除了与之直接交互的下一层之外没有其他知识。

RESTful web 服务

我们已经定义了 REST 和 web 服务,现在可以说 RESTful web 服务是任何与 REST 兼容的 web 服务。

现在,正如我们已经定义了 RESTful web 服务一样,我们需要了解 RESTful web 服务是如何工作的,RESTful web 服务基于什么,以及为什么它们比其他 web 服务(如 SOAP)更受欢迎。

RESTful web 服务的约定

RESTful web 服务基于 RESTful 资源。RESTful 资源是一种实体/资源,主要存储在服务器上,客户机请求使用 RESTful web 服务。就 RESTful web 服务而言,以下是资源的几个特征:

  • 它是一个实体,通常在 URL 中称为名词
  • 它是独一无二的
  • 它有与之关联的数据
  • 它至少有一个 URI

如果你还想知道资源到底是什么,考虑一下博客的例子。在博客系统中,帖子用户类别评论可以是资源。在购物车中,产品类别订单可以是资源。事实上,客户机向服务器请求的任何实体都是资源。

最常见的是,可以对资源执行五种典型操作:

  • 列表
  • 创造
  • 阅读
  • 使现代化
  • 删去

对于每个操作,我们需要两样东西:URI 和 HTTP 方法或动词。

URI 包含作为名词的资源名称和作为动词的 HTTP 方法。要对实体执行某些操作,我们需要有一个名词来告诉我们需要对哪个实体执行某些操作。我们还需要指定一个动词来告诉我们要执行的操作。

对于前面提到的操作,我们在 HTTP 谓词和资源名称中使用 URL 约定。在下一节中,我们将回顾每个操作的 URL 结构和 HTTP 谓词。

HTTP 动词和 URL 结构

下面是如何使用 URI 和 HTTP 谓词组合在资源上执行这些操作。注意,在下面提到的操作的 URI 中,您需要用资源名称替换{resource}

列表操作

  • HTTP 方式:GET
  • URI:/{resource}
  • 结果:返回所提及的资源类型列表。在该列表中,它将为资源提供唯一标识符,这些标识符可用于对该特定资源执行其他操作。

创建操作

  • HTTP 方式:POST
  • URI:/{resource}
  • 参数:可以是POST体内的多个参数
  • 结果:这应该在主体中创建一个带有参数的新资源。
  • 正如您所看到的,Create 和 List 的 URI 没有区别,但是这两个操作是通过 HTTP 方法区分的,这会导致不同的操作。事实上,HTTP 方法和 URI 的组合告诉我们应该执行哪个操作。

读操作

HTTP 方式GET

URI/{resource}/{resource_id}

结果:根据资源 ID 返回记录。

此处resource_id将是可以从列表操作的结果中找到的资源的 ID。

更新操作

可以有两种类型的更新操作:

  • 更新特定记录的某些属性
  • 用新记录完全替换该特定记录

要执行这两个操作,唯一需要更改的是:HTTP 方法。

使用更新操作,要更新资源使用的某些属性,请执行以下操作:

HTTP 方式PATCH

而要取代整个资源使用:

HTTP 方式PUT

URI 和参数将保持不变:

URI/{resource}/{resource_id}

参数:一个查询字符串中可以有多个参数。最初,人们试图在体内传递这些参数,但实际上,PATCHPUT参数是使用查询字符串传递的。

结果:应根据 HTTP 方法更新或替换资源。

这里,resource_id将是可以从列表操作的结果中找到的资源的 ID。同样,实际使用PATCHPUT不会有任何区别,但基于 REST 标准,应该使用PATCH来更新记录的不同属性,而PUT应该用来替换整个资源。

删除操作

  • HTTP 方式DELETE
  • URI/{resource}/{resource_id}
  • 结果:根据 URI 中的资源 ID 删除资源

如果您此刻感到不知所措,不要担心,因为现在我们已经看到了 HTTP 方法和 URI 的哪种组合用于哪种操作。很快,我们将讨论一个案例研究,并将看到不同资源上的一些操作以及示例。

首先,由于我们现在了解了 RESTful web 服务及其工作原理,现在是了解为什么我们更喜欢使用 RESTful web 服务而不是其他 web 服务的好时机。

为什么是 RESTful web 服务?

事实上,RESTful web 服务并不是我们可以编写的唯一 web 服务类型。还有其他编写 web 服务的方法。编写 web 服务既有旧的方法,也有一些较新的方法。我们将不详细介绍其他 web 服务,因为这超出了本书的范围,这里的重点是 RESTful web 服务以及如何构建它们。

休息与肥皂

一个替代 REST 的老方法是 SOAP。事实上,当 REST 作为替代品出现时,SOAP 已经被使用了。一个关键的区别是 SOAP 没有告诉消费者如何访问它的特定约定。SOAP 使用 WSDL 公开其服务。将 WSDL 视为 SOAP 提供的服务的定义。这就是消费者如何知道基于 SOAP 的 web 服务提供了什么以及如何使用它们。

另一方面,REST 强调“c对配置的创新”。如果您像前面一样查看 RESTfulWeb 服务的 URL 结构和 HTTP 谓词,那么有一个固定的约定。例如,如果您在客户端,想要创建一个产品,如果您知道它需要什么参数,那么您可以通过向example.com/product发送POST请求来创建它,然后将创建资源。如果你想列出所有的产品,你可以在GET请求中使用相同的 URL。如果您从列表操作中获得产品 ID,您只需分别使用PATCHPUTDELETE使用example.com/product/{product_id}更新或删除产品即可。要知道使用什么 URL 和 HTTP 方法来执行某种类型的操作非常简单,因为 RESTful web 服务遵循这些约定。因此,客户端的用户只需遵循这些约定,不需要为简单的任务编写大型文档。

除此之外,无状态的简单性、关注点的分离和缓存能力是 RESTful web 服务的一些其他优势,我们已经详细介绍了这些优势。

HTTP 方法的性质

由于我们将主要处理 HTTP 上的 URL,并将使用 HTTP 方法,因此最好花一些时间了解 HTTP 方法的性质。

我们还应该理解,HTTP 方法本身并没有实际执行任何类型的列表、创建或修改。对于某些操作,使用某些 HTTP 方法和 URL 模式只是一种约定。这些方法本身不执行任何操作,但这取决于服务器端开发人员。根据开发人员编写的代码,这些方法可以导致任何操作。

当我们谈论 HTTP 方法的本质时,那么它是关于所遵循的约定和标准。毕竟,RESTfulWeb 服务更倾向于约定而不是配置。今天的 HTTP 和 REST 的基础在于这些约定,而在编写 REST Web 服务时,我们将遵循这些约定。

安全/不安全 HTTP 方法

HTTP 方法可以是安全的,也可以是不安全的。通过 safe,它意味着这些方法不需要更改服务器上的任何资源;通过 safe,它意味着这些方法需要更改服务器上的某些资源。这样一来,我们将GET作为唯一的安全方法,因为它不希望在服务器上更改任何内容,而其他方法,如PUTPOSTPATCHDELETE则被认为是不安全的方法,因为它们希望在服务器上做一些更改。

幂等和非幂等方法

无论我们重复多少次相同的操作,都有一些方法可以达到相同的结果。我们认为 ALE T0T、AUT1、AUT2、和 TY3 T3 作为幂等方法,不管我们重复这些方法调用的次数,总是会产生相同的结果。例如,如果您使用的是GET example.com/books,则无论您使用GET方法调用此 URL 多少次,它都会返回相同的图书列表。然而,若用户在数据库中放入其他内容,那个么它在列表中可能会有不同的结果,但若要声明某个方法幂等元,我们不会考虑由于外部因素而导致结果的变化,而不是方法调用本身。同样,如果您使用PUTPATCH,比如说PATCH``example.com/books/2?author=Ali,无论您使用相同的参数调用此方法多少次,都会得到相同的响应。

DELETE的情况也是如此。无论您在同一资源上调用DELETE多少次,它只会被删除一次。然而,对于DELETE,它也可以根据实现情况而变化。这取决于您作为程序员想要如何实现。您可能想要DELETE并在第一次和随后的通话中给出成功的响应。您可以简单地给出 404,因为资源不再存在。

POST是非幂等的,因为它在服务器上创建了一个新资源,并且响应至少有一个唯一属性(主要是资源的 ID),即使在相同请求参数的情况下所有其他属性都相同。

到目前为止,我们已经了解了 RESTfulWeb 服务约定、URL 模式、HTTP 方法以及 HTTP 方法的本质。然而,这主要是关于请求。URL 和 HTTP 方法都是与请求相关的点。我们还没有看到反应,所以现在让我们来看一看。

HTTP 响应

请求的目的是获得响应,否则就没有用了,考虑到我们还需要了解针对请求预期的响应类型。在这方面,我们将讨论两件事:

  • 响应类型
  • 响应代码

响应类型

在当前世界中,许多人认为 RESTful web 服务的响应必须是 JSON 或具有 JSON 字符串的文本。然而,我们也可以使用 XML 来响应 RESTfulWeb 服务请求。许多人使用 JSON 作为响应,因为它轻量级且易于解析。但同时,这只是一个偏好问题,取决于需求,与 REST 标准无关。

XML 和 JSON 都是格式化数据的方法。XML 代表可扩展标记语言,具有标记语法。JSON 代表 JavaScript 对象表示法,具有类似 JavaScript 对象的语法。有关 JSON 的更多了解,请查看http://www.json.org/

我们将很快研究一个博客的案例研究,并将看到请求和响应示例。在本书中,我们将使用 JSON 作为响应类型,因为 JSON 比 XML 简单。在开发新应用程序时,我们主要使用 JSON,因为它轻量级且易于理解。正如您在以下示例中所看到的,JSON 中的相同数据比 XML 简单得多,并且只包含重要的内容。

在这里,我们试图展示拥有一位或多位作者的书籍的数据:

XML:

<books>
  <book>
    <name>Learning Neo4J</name>
    <authors>
      <author>Rik Van Bruggen</author>
    </authors>
  </book>
  <book>
    <name>
     Kali Linux – Assuring Security by Penetration Testing
    </name>
    <authors> 
      <author>Lee Allen</author>
      <author>Tedi Heriyanto</author>
      <author>Shakeel Ali</author>
    </authors>
 </book>
</books>

现在,让我们看一下 JSON 中的相同示例:

{
books: [
  {
    name:"Learning Neo4J",
    authors:["Rik Van Bruggen"]
  },
  {
    name:"Kali Linux – Assuring Security by Penetration Testing",
    authors:["Lee Allen", "Tedi Heriyanto", "Shakeel Ali"]
  }
 ]
}

从前面的示例中可以清楚地看到,XML 和 JSON 都传递相同的信息。然而,在 JSON 中,显示相同的信息要简单得多,而且所需的单词也要少得多。

因此,在本书的其余部分中,我们将使用 JSON 作为 RESTful web 服务的响应类型。

响应代码

响应代码,也称为 HTTP 状态代码,告诉我们请求的状态。如果 HTTP 请求成功,HTTP 状态代码为 200,表示 OK。如果存在服务器错误,它将返回 500 状态代码,这意味着内部服务器错误。如果请求中出现任何问题,HTTP 状态代码为 400 及以上,其中 400 状态代码表示错误请求。在重定向的情况下,响应代码为 300 及以上。

要查看响应代码及其用法的完整列表,请参见https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

我不会详细介绍它,因为它是多余的,因为所有这些都已经在前面提到的维基百科链接中提供了。但是,我们将在继续讨论时讨论不同的状态代码。

案例研究-博客的 RESTful web 服务端点

为了理解 REST Web 服务,让我们考虑一个博客的案例研究,我们将在博客中讨论资源/实体。我们将开始定义博客资源的需求和端点 URL,然后定义针对这些请求的响应。因此,这些端点和响应定义将帮助我们理解 RESTfulWeb 服务端点应该是什么样子以及响应应该是什么。在后面的章节中,我们将更多地讨论这些端点的实现,因此这些定义将作为下一章的 API 文档。然而,为了简单起见,我们现在将保持它的最小值,稍后再向它添加更多属性。

Although based on HATEOAS, a RESTful web service should return links to the next endpoints and there are conventions that tell us about other endpoints but the API document is still important. API consumers (client-side developers) and API providers (server-side developers) should agree on it so that both can work in parallel without waiting for the other. However, in the real world, we don't have to write API document for basic CRUD operations.

在一个典型的博客中,最常见的资源是帖子和评论。还有其他资源,但现在,为了理解 RESTfulWeb 服务,我们将讨论这两个资源。请注意,我们没有考虑与身份验证相关的内容,但将在后面的章节中对此进行研究。

If client-side and server-side teams are of the same organization, working on a single app, then it is a good idea to get such document created by the client-side team as the server-side team is just the serving client side.

博文

这里,我们列出了博客文章及其端点的需求。对于这些端点,我们将编写一个请求和一个响应。

要求

可以创建、修改、访问和删除博客文章。还有一种方法可以列出所有的博客帖子。因此,我们将列出博客文章的端点。

端点

以下是博客帖子的端点:

创建博客帖子

  • 请求POST /posts HTTP/1.1
  • 车身参数

内容:这是一篇非常棒的帖子 标题:非常棒的帖子

  • 响应
{id:1, title:"Awesome Post", content:"This is an awesome post", link: "/posts/1" }
  • 响应码:201 已创建

这里POST是方法,/posts是 URL(服务器名称后的路径),HTTP 1.1 是协议。在后面的示例中,我们也将继续使用相同的方式来提及请求。因此,请求的第一部分是 HTTP 方法,第二部分是 URL,第三部分是协议。

响应代码告诉客户端资源已成功创建。如果请求参数错误丢失,响应代码应为400,表示请求错误。

阅读博客文章

  • 请求GET /posts/1 HTTP/1.1
  • 响应
{id:1, title:"Awesome Post", content:"This is an awesome post", link: "/posts/1" }
  • 响应代码:200 OK

注意,如果提供 ID 的博客文章(在当前情况下为 1)不存在,则应返回404,表示未找到资源。

更新博客文章

  • 请求PATCH /posts/1?title=Modified%20Post HTTP/1.1
  • 响应
{id:1, title:"Modified Post", content:"This is an awesome post", link:"posts/1" }
  • 响应代码:200 OK

注意,如果提供 ID 的博客文章(本例中为 1)不存在,则应返回响应代码404,表示未找到资源。

此外,我们在更新中使用了 PATCH 而不是 PUT,因为 PATCH 用于修改记录的所有或某些属性,而 PUT 用于修改整个记录,就像用新记录替换旧记录一样。因此,如果我们只使用 PUT 和 pass 一个属性,其他属性将变为空。在补丁的情况下,它只会更新传递的属性,其他属性保持不变。

删除博客文章

  • 请求DELETE /posts/1 HTTP/1.1
  • 响应
{success:"True", deleted_id:1 }
  • 应答码200 OK

Note, if a blog post with an ID provided (in the current case, 1) does not exist, it should return 404, which means resource Not Found.

列出所有博客帖子

  • 请求GET /posts HTTP/1.1
  • 响应
{
data:[
  {
   id:1, title:"Awesome Post", content:"This is an awesome post", link: "/posts/1" 
  },  
  {
   id:2, title:"Amazing one", content:"This is an amazing post", link: "/posts/2"
  }
 ],
total_count: 2,
limit:10,
pagination: {
    first_page: "/posts?page=1",
    last_page: "/posts?page=1",
    page=1
 }
}
  • 应答码:200 OK

在这里,数据是一个对象数组,因为有多个记录返回。除了total_count之外,还有一个分页对象,现在它显示第一页和最后一页,因为记录的total_count只有 2 页。因此,没有下一页或上一页。否则,我们还必须在分页中显示下一个和上一个。

如您所见,分页中有链接,post 对象中也有 post 的链接。我们加入这些链接是为了响应 HATEOAS 约束,该约束规定,如果客户机知道某个入口点,就足以发现相关的端点。

在这里,我们探讨了博客帖子的需求,并定义了其端点的请求和响应。在下一个实体/资源中,我们将在注释中定义端点和响应。

博客帖子评论

这里,我们列出了博客帖子评论的要求,然后是它的端点。对于这些端点,我们将写入RequestResponse

要求

帖子上会有一条、多条或没有评论。因此,可以在博客帖子上创建评论。可以列出博客帖子的评论。可以读取、修改或删除注释。

让我们为这些需求定义端点。

端点

以下是帖子评论的端点:

创建帖子的评论

  • 请求:POST /posts/1/comments HTTP/1.1
  • 车身参数comment: An Awesome Post
  • 应答:
{id:1, post_id:1, comment:"An Awesome Post", link: "/comments/1"}
  • 应答码:201 Created

这里是评论的例子,是针对某个博客帖子创建的评论。因此,请求 URL 也包括post_id

阅读评论

  • 请求:GET /posts/1/comment/1 HTTP/1.1GET /comment/1 HTTP/1.1

第二个似乎更合理,因为只需要有评论的 ID,而不必担心该评论的 post ID。由于评论的 ID 是唯一的,我们不需要拥有帖子的 ID 来获取评论。因此,我们将继续第二个 URL,即GET /comment/1 HTTP/1.1

  • 应答:
{id:1, post_id:1, comment:"An Awesome Post", link: "/comments/1"}
  • 应答码:200 OK

因为任何评论都只能针对某个帖子,所以回复中也包括post_id

更新评论

  • 请求:PATCH /comment/1?comment="Modified%20Awesome%20Comment' HTTP/1.1
  • 应答:
{id:1, post_id:1, comment:"Modified Awesome Comment", link: "/comments/1"}
  • 应答码:200 OK

在这里,我们使用了补丁,因为我们想要更新注释的单个属性。此外,您还可以看到%20传入了一条新的注释。所以,%20只是一个空格的替代品,因为 URL 不能包含空格。因此,使用 URL 编码时,空格应始终替换为%20

删除帖子评论

  • 请求:DELETE /comments/1 HTTP/1.1
  • 应答:
{success:"True", deleted_id:1 }
  • 应答码:200 OK

注意,如果提供 ID 的帖子评论(在本例中为 1)不存在,则应返回404未找到

列出特定帖子的所有评论

  • 请求:GET /posts/1/comments HTTP/1.1
  • 应答:
{
data:[
  {
   id:1, comment:"Awesome Post", post_id:1, link: "/comments/1" 
  }, {
   id:2, comment:"Another post comment", post_id:1, link: "/comments/2"
  } 
 ], 
 total_count: 2,
 limit: 10,
 pagination: {
 first_page: "/posts/1/comments?page=1",
 last_page: "/posts/1/comments?page=1",
 page=1 
 } 
}
  • 应答码:200 OK

如您所见,帖子的评论列表与博客帖子的列表非常相似。并且它有total_count和分页方式相同。它现在显示第一页和最后一页,因为记录的total_count只有 2。所以没有下一页或上一页。否则,我们还必须在分页中显示下一个和上一个链接。

通常,在博客上看不到带有注释的分页,但最好保持一致,在列表中有分页。因为一篇文章可能会有很多评论,我们应该对其加以限制,所以我们需要分页。

更多资源

尽管我们试图以一种通过示例获得实用知识的方式来研究 RESTfulWeb 服务,但下面是一些其他有趣的资源。

罗伊·菲尔丁介绍 REST 的论文:

http://www.ics.uci.edu/~fielding/pubs/demission/top.htm

与 Roy Fielding 的回答进行小组讨论:

https://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/6735

这是stackoverflow.com上关于 REST 与 SOAP 的一条有趣的线索:

http://stackoverflow.com/questions/19884295/soap-vs-rest-differences

罗伊·菲尔丁谈论休息:

https://www.youtube.com/watch?v=w5j2KwzzB-0

看待 REST 的另一种方式:

https://www.youtube.com/watch?v=RY_kMXEJZfk

总结

在本章中,我们了解了什么是 RESTful web 服务。我们研究了作为 RESTful web 服务调用应该满足的约束。然后我们理解了 REST 是一种架构,它是一种构建东西的方式,它支持约定而不是配置。我们研究了 HTTP 动词(方法)和 URL 约定。我们理解这些只是惯例。HTTP 动词和 URL 用于 RESTful web 服务;否则,总是由开发人员来提供预期的行为,因为 REST 具有被视为标准的约定,但它不提供任何实现。

在本章中,我们没有讨论 RESTfulWeb 服务的实现。我们只考虑了一个典型博客的案例研究,并以该博客的两个资源为例,用预期的响应定义了它们的端点。我们还研究了 HTTP 响应代码,但没有编写实现这些 RESTful web 服务的实际代码。我们定义了这些端点,因此我们将在下一章中看到它们的实现。

由于本书是关于在 PHP7 中构建 RESTful web 服务的,因此在下一章中,我们将介绍 PHP7 中的特性。PHP7 不提供任何特定于 RESTful web 服务的功能,但我们将利用 PHP7 中的一些新特性编写更好、更干净的代码来构建 RESTful web 服务。

如果您已经很了解 PHP7,并且现在不想深入研究它,那么您可以跳过第 2 章PHP7,以便更好地编码,然后开始第 3 章创建 RESTful 端点,在那里我们将构建 RESTful web 服务。