Каков "правильный" способ создания отношений "многие ко многим" в Restful API


Я пытаюсь найти наилучшую практику для того, чтобы создать отношения "многие ко многим" в Restful API. Usecase действительно прост, но я не могу найти "правильный" способ сделать это.

В нашей модели у нас есть ребенок, которые связаны со многими отношениями к опекуну. В таблице отношений у нас есть 2 дополнительных параметра, типа (родитель, няня, чрезвычайная ситуация и т. д.) и активный (логический).

Вы можете только добавить опекун существующему ребенку, но существующий опекун может быть связан с другим ребенком.

Сегодня мы делаем это так

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

Это создатьопекуна и добавить его к ребенку. Но с помощью этого метода мы не можем справиться с тем случаем, когда я хочу добавить существующего опекуна К ребенку. Вот ответы, которые я нашел, чтобы представить это, но я не знаю, какой из них является лучшим (и спокойным) способом (возможно, ни один из них они хорошие...):

Решение 1 - сохранить конечную точку как сегодня

Но поместите необязательное полеid в полеguardian . Если id пуст, API должен создать ressource в противном случае просто получить его и обновить значения, если это необходимо.

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/

Потому что на самом деле это не источник "опекун", а источник "ребенок-опекун" (отношения). Мне это не очень нравится, потому что со старым URI мы можем более легко предположить, что

GET kids/{kidID}/guardians/

Даст вам всех опекунов, связанных с ребенком, но не этого

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

Воля удалите связь, а не опекуна .

Так что, как вы понимаете, я действительно заблудился и был бы признателен вам за помощь.

С наилучшими пожеланиями,

2 2

2 ответа:

Нельзя ли создать третью категорию ресурсов для самого отношения, например "охранника", не подчиненного экземпляру других ресурсов? По-видимому, это рекомендуемый и обычный способ работы с отношениями n к n в базах данных.

GET /guards?kid="Johnny" даст вам список отношений, которые вы могли бы использовать, чтобы получить все его опекуны. GET /guards?guard="Kelly", Вы можете догадаться. /kids и /guards сохраняли бы данные только о самих ресурсах, и, вероятно, было бы проще поддерживать, чем если вы должны сохранить данные отношений как часть их.

Я думаю, что вы могли бы сделать это более спокойным, используя ссылки на каждый член отношения вместо числовых идентификаторов. И вы можете иметь поле типа " отношения "в представлениях детей и опекунов с URL+строкой запроса, необходимой для получения их конкретных" охранников", которые могут кому-то понадобиться.

Я пойду с ответом 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}/"
}

"проблема", которую я видел с другими моими методами, заключается в том, что /kids/{kidID}/guardians/ и /guardians/ не будут представлять один и тот же вид ресурсов, но будут иметь одно и то же имя.