REST:各个资源之间的关系

REST: Relations between individual resources

谁能告诉我如何 "RESTfully" 在两个单独的资源之间创建关系?
我想出了几种方法,但我想坚持标准。
我会列出几个例子来向你们展示我已经想到的东西。
示例将有一个 post 资源,必须 linked 到类别资源。

注意:所有示例都假定这两个资源已经存在。

示例 1:

PATCH /post/1 HTTP/1.1
Host: api-host
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{
    "post": {
        "links": {
            "category": "2"
        }
    }
}

示例 2:

POST /post/1/category/2 HTTP/1.1
Host: api-host
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{}

示例 3:

POST /relations?post=id&category=id
Host: api-host
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{}

删除这两个资源之间关系的最佳方法是什么?

"Solution":
由于不再支持 LINK 和 UNLINK,最佳解决方案 imo(帽子提示@Bramus)将是 PATCH 示例。

因此,要创建一个 link,您可以调用:

PATCH /post/1 HTTP/1.1
Host: api-host
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{
    "post": {
        "links": {
            "category": "2"
        }
    }
}

并删除它:

PATCH /post/1 HTTP/1.1
Host: api-host
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache

{
    "post": {
        "links": {
            "category": ""
        }
    }
}

要将 Post 放入 Category 我会使用一个简单的 PATCH 将所有这些 categories 作为数组传递(如果可以选择多个类别),或单个 category 键值对。

  • 多个类别:

    PATCH /post/1 HTTP/1.1
    Host: api-host
    Accept: application/json
    Content-Type: application/json
    Cache-Control: no-cache
    
    {
        "categories": [2, 3]
    }
    
  • 单个类别:

    PATCH /post/1 HTTP/1.1
    Host: api-host
    Accept: application/json
    Content-Type: application/json
    Cache-Control: no-cache
    
    {
        "category": 2
    }
    

它类似于您的第一个示例,但它在类别中作为数组/单个值传递时略有不同。我更喜欢这种方法,因为它模仿了通过普通 HTML 表单所做的事情:多个类别的多个复选框(结果是一个被发布的数组)或一个下拉列表(结果是被发布的单个值)。

在旁注中,我没有将类别视为 link,而是 sub-entity/sub-resource:

  • 子实体表示两个 (主要是不同类型的) 实体之间的关系。
  • 链接主要用于导航(nextprevparentme、...)

在您的 PATCH 中使用 links 密钥与此意识形态不兼容。

您已经接受了与您使用 PATCH 的尝试相关的答案,但我想提出一个替代解决方案。我将从非常简单的事情开始。将一个新的 link 添加到您的 Post 资源类型中,用于它可以放入的每个类别。

在 HAL 中它看起来像这样:

x:category-add : [
    { "href" : "url/to/add/post/x/to/category/1", title : "Add Category 1"},
    { "href" : "url/to/add/post/x/to/category/2", title : "Add Category 2"},
    { "href" : "url/to/add/post/x/to/category/3", title : "Add Category 3"},
    { "href" : "url/to/add/post/x/to/category/4", title : "Add Category 4"},
]

那就太简单了。客户端需要知道的信息要少得多才能执行您将 post 添加到类别的用例。他们永远不必存储 URLs 并且知道将它们放在某个模板中的什么地方。

或者,您可以使用名称字段来指示 post 是否已经是成员。类似于:

x:category : [
    { "href" : "url/to/add/post/x/to/category/1", name : "add", title : "Add Category 1"},
    { "href" : "url/to/remove/post/x/to/category/2", name : "remove", title : "Remove Category 2"},
    { "href" : "url/to/add/post/x/to/category/3", name : "add", title : "Add Category 3"},
    { "href" : "url/to/remove/post/x/to/category/4", name : "remove", title : "Remove Category 4"},
]

从这里您可能会发现类别太多,每个类别都有一个 link 可能很麻烦。答案是从您的 post 资源中 link 编辑的中间资源。称之为 post-类别管理。 Link 通过 x:post-category-management 这样的关系从您的 Post 发送给它。让这个资源允许通过类别分页、模糊搜索类别、某种删除所有类别的方法、提供建议的类别。

{
  x:category-suggested : [
    { href : "path/to/add/suggeted/category/Z", title : "Category Z"}
  ],
  x:category-available : [
    { "href" : "url/to/add/post/x/to/category/1", title : "Add Category 1"},
  ],
  next : { href : "url/to/next/available/categories" },
  x:category-search : { href : "url/to/search/for/categories/for/post/x{?term}", templated : true}
}

这对我来说似乎简单多了。帮助我得到她的是使用 RESTful 体系结构对 Web 应用程序进行成像,以及如果我没有 javascript 和表单控件,我希望它具有哪些类型的 link。随着想象中的应用程序变得越来越复杂,很明显每个 post 都需要一个类别管理页面。 html 页 ISA 资源。

一旦开始,我就会开始支持一些更高级的东西。就像发送到应用类别 URL 的 DELETE 动词一样,将它们从 post 中删除。对我来说,即使 post 属于类别,我也可以认为类别属于 post。在实体关系图中,它是您实际要删除的 link,并且 DELETE 将与 link 的 URL 一起发送,而不是实际类别。

也许那时我会支持真正的 PATCH 请求(其中请求实体是像 jsonpatch 这样的补丁请求)以允许非常高级的客户端行为。