在 Restful API 中创建 many-to-many 关系的 "right" 方法是什么

What's the "right" way to create a many-to-many relationship in a Restful API

我试图找到最佳实践,以便在 Restful API 中创建 Many-to-Many 关系。用例非常简单,但我真的找不到“正确”的方法。

在我们的模型中,我们有 KidGuardian 有 Many-to-Many 关系。在关系 table 中,我们有 2 个额外的参数,type(parent、nanny、emergency 等)和 active(布尔值)。

您只能将 Guardian 添加到现有的 Kid,但现有的 Guardian 可以link 和另一个 Kid.

今天,我们就是这样做的

POST kids/{kidID}/guardians
{
    "type": "parent"
    "active": false 
    "guardian": {
        "first_name": "foo"
        "last_name": "bar"
    }
}

这将创建 Guardian 并将其添加到 Kid。但是,使用这种方法我们无法处理我想将现有 Guardian 添加到 Kid 的情况。在这里我找到的答案是为了表示这个,但我不知道哪一个是最好的(和 restful)方式(也许 none 是好的......):

解决方案 1 - 保持今天的端点

但是把一个non-mandatoryid字段给guardian。如果 id 为空,API 必须创建资源,否则只需检索它并在需要时更新值。

POST kids/{kidID}/guardians/
{
    "type": "parent"
    "active": false 
    "guardian": {
        "id": "ab65f263-dd3d-bbc6-8b7b-57a3b4b26c21"
    }
}

解决方案 2 - 在 2 个调用中中断此端点

# Create the Guardian
POST guardians/
{
    "first_name": "foo"
    "last_name": "bar"
}

# This method can only "link" the models
POST kids/{kidID}/guardians/
{
    "type": "parent"
    "active": false 
    "guardian_id": "ab65f263-dd3d-bbc6-8b7b-57a3b4b26c21"
}

[已编辑] 解决方案 2.5 - 使用 PUT

创建关系

和以前一样,您必须创建监护人,但为了添加关系,您需要创建一个

PUT kids/{kidID}/guardians/{guardianID}
{
    "type": "parent"
    "active": false 
}

辅助解决方案:在第二个选择中我们可以通过以下方式更改资源的URI:

POST kids/{kidID}/kid-guardians/

因为它实际上并不是 POST 一个 "guardian" 资源,而是一个 kid-guardian 资源(关系)。我不太喜欢它,因为使用旧的 URI 我们可以更容易地假设

GET kids/{kidID}/guardians/

会给你所有 Guardians 与 Kid 有关,但不会

DELETE kids/{kidID}/guardians/{guardianID}

将删除关系而不是 Guardian

如您所知,我真的很迷茫,非常感谢您的帮助。

此致,

是否可以为关系本身创建第三类资源,例如 "guard",不从属于其他资源的实例?这似乎是处理数据库中 n 对 n 关系的推荐和常用方法。

GET /guards?kid="Johnny" 会给你一个关系列表,你可以用它来获得所有监护人。 GET /guards?guard="Kelly",你猜对了。 /kids/guards 将仅保留有关资源本身的数据,并且可能比必须将关系数据保留为资源的一部分更容易维护。

我认为您可以通过使用关系中每个成员的链接而不是数字 ID 来获得更多 RESTful。你可以在孩子和监护人的表示中有一个像 "relationships" 这样的字段,需要 URL+ 查询字符串来检索他们的特定 "guards" 可能有人需要它们。

我将采用 Fabricio Rocha 的答案,实现方式如下:

POST guardian-kids/
{
    "type": "parent",
    "guardian": {
        "id": "{guardianId}"
    },
    "kid":{
        "id": "{kidId}"
    }
}

如果你想找回守护小子

GET guardian-kids/{GuardianKidId}
{
    "type": "parent",
    "guardian": {
        "id": "{guardianId}",
        "url": "guardians/{guardianId}/"
    },
    "kid": {
        "id": "{kidId}",
        "url": "kids/{kidId}/"
    },
    "url": "guardian-kids/{GuardianKidId}/"
}

我也做了这两个终点(你只能在那些上得到)

GET kids/{kidId}/guardian-kids
{
    "type": "parent",
    "guardian": {
        "id": "{guardianId}",
        "url": "guardians/{guardianId}/"
    },
    "kid": {
        "id": "{kidId}",
        "url": "kids/{kidId}/"
    },
    "url": "guardian-kids/{GuardianKidId}/"
}

GET guardians/{guardianId}/guardian-kids
{
    "type": "parent",
    "guardian": {
        "id": "{guardianId}",
        "url": "guardians/{guardianId}/"
    },
    "kid": {
        "id": "{kidId}",
        "url": "kids/{kidId}/"
    },
    "url": "guardian-kids/{GuardianKidId}/"
}

我在其他方法中看到的"problem" /kids/{kidID}/guardians/ 和 /guardians/ 不会代表相同类型的资源,而是具有相同的名称。