23

我目前正在设计一个 REST Http api。(使用 HATEOAS 的东西,让客户“更简单”,避免客户做复杂的事情,而不是让 api 告诉他们该做什么......)

由于应用程序的社交特性,为了与应用程序交互,需要对用户进行身份验证,每个用户对数据的“视图”都会略有不同。我们以推特为例,它对每个人都会更容易。

为了对用户进行身份验证,我们将使用 OAuth,很简单。

因此,在客户端(ios 应用程序...)中,随机用户可能会看到一个用户列表,应该看到:

Adrien: Following
John:   Not Following
Rambo:  Not Following

另一个用户可能会看到:

Adrien: Following
John:   Not Following
Rambo:  Following

为了实现这一点,第一个解决方案是客户端(在 oauth 术语中,iphone/web/etc 应用程序)获取经过身份验证的用户关注的所有用户的列表,并且每次客户端显示列表时,比较每个具有关注用户列表的用户,以了解它是否应该显示“未关注”或“关注”。

请求/响应将是:

GET /users
Authorization: OAuth token...

[
  {"id": 1, "name": "Adrien"},
  {"id": 2, "name": "John"},
  {"id": 3, "name": "Rambo"}
]

GET /users/{myid}/following
Authorization: OAuth token...

[1, 3, 25, 1210, 9]

这似乎是相当的,无国籍的。好的。

现在,如果我想让客户端开发人员的生活更轻松,并直接在用户列表响应中嵌入每个用户相对于经过身份验证的用户的关系,该怎么办:

GET /users
Authorization: OAuth token...

[
  {"id": 1, "name": "Adrien", "relationship": "Following"},
  {"id": 2, "name": "John", "relationship": "Not Following"},
  {"id": 3, "name": "Rambo", "relationship": "Following"}
]

所以,问题:

  • 它似乎打破了“无状态”的东西,它真的打破了REST无状态约束吗?
  • 接下来,您认为 api 这样做是好还是坏?
4

5 回答 5

16

您绝对应该将关系嵌入到用户列表响应中。强迫客户计算它是不好的做法。

这不会破坏 REST 的无状态约束,因为它是无状态的交互,而不是系统。服务器几乎总是必须存储和维护状态。例如,服务器将需要维护谁在关注谁的状态。

最后,我认为您并没有完全理解 Hypermedia 作为应用程序状态引擎的“状态”部分。基本上,资源是状态机。当您GET使用资源时,呈现的有效状态转换在响应中具有超媒体控件(链接和表单)。通过这些链接并提交表单,客户可以更改这些资源的状态。

于 2012-07-21T23:22:51.570 回答
13

在响应正文中包含关系类型的描述并没有打破无状态约束。无状态约束意味着 Web 服务器可以响应请求而不依赖于任何先前的请求(正如TomJacobkgb所提到的)。

我没有资格说您所做的是否是“最佳实践”,但总的来说,Roy 给出了以下支持和反对使您的 API 无状态的原因(参见他的论文的第 5.1.3 节)。就像生活中的许多事情一样,需要权衡取舍:

无状态系统的问题

  • 请求可能需要更大。由于请求之间没有将数据存储在服务器上,因此每个请求可能需要一遍又一遍地包含相同的内容。

  • 在无状态系统中,服务器依赖于客户端正确维护状态。

无状态系统的好处

  • 您仅根据请求的内容就知道请求试图实现什么。

  • 可靠性,因为它“简化了从部分故障中恢复的任务”。有关更多信息,请参阅Roys 论文中引用的参考文献 133

  • 改进的可扩展性。管理请求之间的状态,尤其是在分布式环境中,可能非常复杂。这里首先想到的是ASP.NET InProc session state,它适用于单个服务器、单个进程实例,但它不能很好地扩展。

RESTful 资源

此外,根据 Roy 对资源的定义,我对我认为您定义资源的方式提出质疑,每个用户对数据的“视图”略有不同。Roy 将资源定义为随时间变化的隶属函数(参见论文中的第 5.2.1.1 节)。您在上面定义的用户列表资源因时间和 Authorization 标头而异。两个不同的客户端同时请求 /users 很可能会得到完全不同的结果。这将使缓存结果更加困难。

编辑:使用 HTTP 变化标头将允许它被缓存。

于 2012-07-23T15:08:09.253 回答
4

如果您认为向打破无状态约束的用户添加“关系”属性,那么在请求中包含“/following”时添加它也会破坏它。

我会说“无状态”意味着没有响应取决于其他请求/响应。

HTTP 是一种无状态协议,但它可以在请求/响应标头中存储大量有关用户的数据(我不是在谈论会话/cookies)

于 2012-07-18T09:29:45.727 回答
3

来自 Roy Fieldings架构风格和基于网络的软件架构的设计

3.4.3 Client-Stateless-Server (CSS)

The client-stateless-server style derives from client-server with the additional
constraint that no session state is allowed on the server component. 
Each request from client to server must contain all of the information necessary 
to understand the request, and cannot take advantage of any stored context on 
the server. Session state is kept entirely on the client.

链接: http: //www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

因此,您直接在响应中嵌入实体数据不会使您的解决方案成为无状态的。

关于良好做法:

实际提供用户数据比提供数字列表让客户弄清楚如何处理要好得多。

但是,根据每个用户的数据量,您可以考虑提供指向用户资源的链接列表并声明“关注”关系。然后客户端可以获取所需用户的详细信息。您选择哪种解决方案应取决于您认为客户将需要什么,您最终可能会使用多种方法。

于 2012-07-21T23:35:30.907 回答
1

我没有看到将“关系”信息嵌入/users资源和无状态约束之间的相关性。所以我认为没有问题。

但是,我认为您正在打破“资源识别”约束。

/Users对你和/Users对我来说,这将展示一组完全不同的关系。我认为这是两种不同的资源,因此应该有不同的 URI。

在某些情况下,您可以根据用户是谁(例如出于安全原因)更改表示,但这种情况对我来说变化太大了。

于 2012-08-29T12:53:52.887 回答