RESTful 编程到底是什么?
REST是 Web 的底层架构原则。Web的惊人之处在于,客户端(浏览器)和服务器可以以复杂的方式进行交互,而客户端无需事先了解服务器及其托管的资源。关键约束是服务器和客户端都必须就使用的媒体达成一致,在 Web 的情况下是HTML。
遵循REST原则的 API不需要客户端了解 API 的结构。相反,服务器需要提供客户端与服务交互所需的任何信息。一个HTML表格是这样一个例子:服务器指定资源和所需的字段的位置。浏览器事先不知道在哪里提交信息,也不事先知道要提交什么信息。两种形式的信息都完全由服务器提供。(这个原理被称为HATEOAS : Hypermedia As The Engine Of Application State。)
那么,这如何应用于HTTP,以及如何在实践中实现呢?HTTP以动词和资源为导向。主流用法中的两个动词是GETand POST,我想大家都会认识的。但是,HTTP标准定义了其他几个标准,例如PUT和DELETE。然后根据服务器提供的指令将这些动词应用于资源。
例如,假设我们有一个由 Web 服务管理的用户数据库。我们的服务使用基于 JSON 的自定义超媒体,我们为其分配 mimetype application/json+userdb(也可能有一个application/xml+userdb和application/whatever+userdb-可能支持许多媒体类型)。客户端和服务器都被编程来理解这种格式,但他们对彼此一无所知。正如罗伊菲尔丁指出的那样:
mimetype application/json+userdb
application/xml+userdb
application/whatever+userdb-
REST API 应该花费几乎所有的描述性工作来定义用于表示资源和驱动应用程序状态的媒体类型,或定义扩展关系名称和/或现有标准媒体类型的超文本启用标记。
对基础资源的请求/可能会返回如下内容:
要求
GET / Accept: application/json+userdb
回复
200 OK Content-Type: application/json+userdb { "version": "1.0", "links": [ { "href": "/user", "rel": "list", "method": "GET" }, { "href": "/user", "rel": "create", "method": "POST" } ] }
我们从媒体的描述中知道,我们可以从称为“链接”的部分中找到有关相关资源的信息。这称为超媒体控件。在这种情况下,我们可以从这样的部分中得知,我们可以通过发出另一个请求来找到用户列表/user:
GET /user Accept: application/json+userdb
200 OK Content-Type: application/json+userdb { "users": [ { "id": 1, "name": "Emil", "country: "Sweden", "links": [ { "href": "/user/1", "rel": "self", "method": "GET" }, { "href": "/user/1", "rel": "edit", "method": "PUT" }, { "href": "/user/1", "rel": "delete", "method": "DELETE" } ] }, { "id": 2, "name": "Adam", "country: "Scotland", "links": [ { "href": "/user/2", "rel": "self", "method": "GET" }, { "href": "/user/2", "rel": "edit", "method": "PUT" }, { "href": "/user/2", "rel": "delete", "method": "DELETE" } ] } ], "links": [ { "href": "/user", "rel": "create", "method": "POST" } ] }
我们可以从这个回应中看出很多。例如,我们现在知道我们可以通过POSTing 来创建一个新用户/user:
POST /user Accept: application/json+userdb Content-Type: application/json+userdb { "name": "Karl", "country": "Austria" }
201 Created Content-Type: application/json+userdb { "user": { "id": 3, "name": "Karl", "country": "Austria", "links": [ { "href": "/user/3", "rel": "self", "method": "GET" }, { "href": "/user/3", "rel": "edit", "method": "PUT" }, { "href": "/user/3", "rel": "delete", "method": "DELETE" } ] }, "links": { "href": "/user", "rel": "list", "method": "GET" } }
我们还知道我们可以更改现有数据:
PUT /user/1 Accept: application/json+userdb Content-Type: application/json+userdb { "name": "Emil", "country": "Bhutan" }
200 OK Content-Type: application/json+userdb { "user": { "id": 1, "name": "Emil", "country": "Bhutan", "links": [ { "href": "/user/1", "rel": "self", "method": "GET" }, { "href": "/user/1", "rel": "edit", "method": "PUT" }, { "href": "/user/1", "rel": "delete", "method": "DELETE" } ] }, "links": { "href": "/user", "rel": "list", "method": "GET" } }
请注意,我们使用不同的HTTP动词(GET,PUT,POST,DELETE等)来操纵这些资源,我们假设一客户端的部分仅有知识是我们媒体的定义。