使用超媒体链接时如何处理对REST资源的更新

使用超媒体链接时如何处理对REST资源的更新,rest,hateoas,Rest,Hateoas,我正在开发一个REST-ful API,其中的资源是相互关联的。资源相互引用,可以创建或删除这些引用。当资源使用超链接相互引用时,我有点不确定如何支持将资源关联在一起 下面是一个简单的示例,其中包含两个资源A和B 现在,A的文档中不包含B,而是包含指向它的链接。当使用超媒体时,它可能看起来像这样: 如果用户希望添加或删除a列表中的某个B引用,考虑到超链接的存在,他们如何添加或删除?我希望用户能够在一次PUT操作中更新整个A资源,但输出中没有任何内容指示B需要哪个值。对我来说,用户使用以下内容执行

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

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

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

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

并接收更新的资源(在响应中),如下所示:

我担心的是,在更新资源A的
列表\u b
时,用户不一定知道要在资源中包含什么

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


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

HATEOAS在RESTful接口中将资源连接在一起,这里不清楚您所描述的辅助对象作为独立资源是否真的有意义。HATEOAS的“AS”部分提醒我们Web页面在Web应用程序中作为“资源”所起的作用。每个Web页面实际上是应用程序状态的交互式表示(本例中的“应用程序”是一个经典的多页面Web应用程序),而指向其他资源的超链接为用户提供了到其他应用程序状态的转换

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

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

如果答案是“否”,那么它们显然不应该在“A”结构中被夸大。然而,我认为答案是“是的”,并且您也有很好的理由提供您称之为独立资源的所有其他辅助对象。在这种情况下,无论发生什么情况,都需要一些路由和控制器形式的接口工作来支持所有这些资源,因为您的应用程序可能提供了一种方法来单独操作它们,或者至少查询它们(通过超链接,如示例中的超链接)

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


ID值有点麻烦,因为您可能会试图通过从URL文本中提取ID值来破坏后端的封装。真正的HATEOAS狂热者让他们的RESTful API生成模糊的、散列的或其他不可理解的URL,以阻止客户端破坏这种封装。更好的是,新“B”对象的POST在其响应体中返回新“B”对象的完整表示,包括其ID,以便客户端可以重新构造完整对象并从中提取ID,因此,将耦合范围缩小到资源本身,而不是获取资源的RESTful接口的细节。

您还应该查看:

LINK/ResourceA/1http/1.1
链接:;rel=“列表b”
...
是的,很好,随便吧

这告诉/ResourceA/1使用关系“list_b”链接到/ResourceB/3。

谢谢您的想法。您是对的,我正在使用的资源要复杂得多,并且确实有自己的使用模型作为一流资源(我的示例非常简单)。此API中的所有资源创建确实会在location标头中返回URL,因此听起来您的意思是列表_b可能仅包含URL(无ID),客户端无论如何都应该包含URL。如果用户希望将现有的B资源添加到此列表中,他们将使用URL。这是一个公平的解释吗?是的,不知道更多的细节,我会说这是一个公平的解释。再次感谢。那么,您是否主张实体体中的所有资源引用(我知道,这是一个全面的概括)
Resource A:
  name: integer
  list_b: [list of resource B]

Resource B:
  id: integer
  description: String
Resource A:
{
    id: 1,
    list_b: [
        { id: 1, href: "https://server/api/b/1" },
        { id: 2, href: "https://server/api/b/2" }
    ]
}
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" }
    ]
}
LINK /ResourceA/1 HTTP/1.1
Link: <http://example.com/ResourceB/3>; rel="list_b"
...

204 Yeah Fine, Whatever