4

我正在使用一个 REST-ful API,其中的资源是相互关联的。资源相互引用,这些引用可能被创建或删除。当它们使用超链接相互引用时,我有点不确定如何支持将资源关联在一起。

下面是一个简单的示例,其中包含两个资源 A 和 B。

Resource A:
  name: integer
  list_b: [list of resource B]

Resource B:
  id: integer
  description: String

现在,A 的文档中不包含 B,而是指向它的链接。使用超媒体时,它可能看起来像这样:

Resource A:
{
    id: 1,
    list_b: [
        { id: 1, href: "https://server/api/b/1" },
        { id: 2, href: "https://server/api/b/2" }
    ]
}

如果用户想在 A 的列表中添加或删除 B 引用之一,考虑到超链接的存在,他们如何做到这一点?我希望用户能够在一次 PUT 操作中更新整个 A 资源,但输出中没有任何内容表明 B 需要哪个值。用户使用以下内容执行 PUT 对我来说很有意义:

Resource A:
{
    id: 1,
    list_b: [
        { id: 1, href: "https://server/api/b/1" },
        { id: 2, href: "https://server/api/b/2" },
        { id: 3 },
    ]
}

并像这样接收更新的资源(在响应中):

Resource A:
{
    id: 1,
    list_b: [
        { id: 1, href: "https://server/api/b/1" },
        { id: 2, href: "https://server/api/b/2" },
        { id: 3, href: "https://server/api/b/3" }
    ]
}

我担心的是,用户在更新资源 A's 时不一定知道要在资源​​中包含什么list_b

在处理从一个资源到另一个资源的超链接时,创建和更新应该如何工作?是否应该允许客户端更新链接的一部分 (the id),还是应该要求他们更新链接的两个部分?

注意:我知道另一种方法可能是公开资源 A 的子 URL。它可以公开list_b为可通过 HTTP 操作的资源(允许客户端在列表资源本身上使用 POST、PUT 和 DELETE)。但是当 A 包含对其他资源类型的多个引用时,这似乎不太合理。引用另一个字段的每个字段都可能需要一个子 url,如果有 10 个以上的字段,则该子 url 很笨拙,并且需要多个 HTTP 请求来更新资源。

4

2 回答 2

2

HATEOAS 在 RESTful 接口中将资源连接在一起,这里不清楚您所描述的附属对象作为独立资源是否真的有意义。HATEOAS 的“AS”部分提醒我们网页在 Web 应用程序中作为“资源”所扮演的角色。每个 Web 页面实际上是应用程序状态的交互式表示(在这种情况下,“应用程序”是一个经典的多页面 Web 应用程序),并且到其他资源的超链接为用户提供了到其他应用程序状态的转换。

RESTful Web API 以 JavaScript 代码而不是人类作为其客户端,自然是面向数据访问的,因此很少有资源采用“应用程序状态”形式本身。在传统的 Web 应用程序中,您可以绘制状态转换图,并清楚地看到状态之间的联系,从而清楚地看到资源之间的联系。在 RESTful API 中,被动数据资源之间的边界更多地受到客户端/服务器交互的效率和其他微妙力量的推动。

那么你这里的附属对象(“B”)真的需要被表示为一等资源吗?是否存在前端将独立于它们参与的聚合(“A”)枚举或以其他方式访问它们的实例?

如果答案是“否”,那么它们显然不应该在“A”结构中以超文本形式表示。但是,我认为答案是“是”,并且您也有充分的理由提供您所指的所有其他附属对象作为独立资源。在这种情况下,无论如何都需要以路由和控制器的形式进行一些接口工作,以支持所有这些资源,因为您的应用程序可能提供了一种单独操作它们的方法,或者至少是查询它们(通过您的示例中的超链接)。

在这种情况下,表示您的“B”对象集合(例如,“server/api/b”)的路径的 POST 可以在响应的“位置”标头值中返回一个 URL,因为应该创建新资源的 POST做。当您的用户以交互方式将新的“B”添加到您网页上属于“A”的列表时,您的前端可以首先发布新的“B”,成功时通过位置标头获取其 URL。然后,它可以将该链接合并到其“A”对象内的列表表示中,然后再放置更新的“A”。

ID 值有点麻烦,因为您很想通过从 URL 的文本中提取 ID 值来破坏后端的封装。真正的 HATEOAS 狂热者让他们的 RESTful API 产生混淆、散列或其他难以理解的 URL,专门用来阻止客户端的这种封装破坏。更好的是新“B”对象的 POST 在其响应正文中返回新“B”对象的完整表示,包括其 ID,以便客户端可以重构完整对象并从中提取 ID,从而缩小与资源本身的耦合,而不是获取资源的 RESTful 接口的细节。

于 2013-03-14T18:02:43.310 回答
1

You should also look at the LINK method:

LINK /ResourceA/1 HTTP/1.1
Link: <http://example.com/ResourceB/3>; rel="list_b"
...

204 Yeah Fine, Whatever

This tells /ResourceA/1 to link to /ResourceB/3 using the relationship "list_b".

于 2013-05-29T13:05:30.600 回答