Який найкращий зразок для додавання наявного елемента до колекції в API REST?


23

Я розробляю прагматичний API REST, і я трохи застряг у тому, як найкраще додати існуючі сукупності до колекції. Моя модель домену включає проект, який має колекцію Сайтів. Це суворий зв'язок між багатьма і багатьма, і мені не потрібно створювати сутність, яка явно моделює відносини (тобто ProjectSite).

Мій API дозволить споживачам додати існуючий сайт до проекту. Де я зависаю, це те, що мені потрібні єдині дані ProjectId та SiteId. Моя початкова ідея:

1. POST myapi/projects/{projectId}/sites/{siteId}

Але я теж подумав

2. POST myapi/projects/{projectId}/sites

із об'єктом сайту, надісланим як вміст JSON.

Варіант 1 простий і працює, але не дуже добре, і у мене є інші стосунки, які не можуть слідувати цій схемі, тому це додає непослідовність мого API.

Варіант 2 відчуває себе краще, але призводить до двох проблем:

  • Чи слід створити Сайт або викинути виняток, якщо розміщено новий Сайт (SiteId = 0)?
  • Оскільки мені потрібні лише ProjectId і SiteId для створення взаємозв'язку, Сайт може бути розміщений з неправильними або відсутніми даними для інших ресурсів.

Третій варіант - надання простої кінцевої точки виключно для створення та видалення відносин. Ця кінцева точка очікувала б корисну навантаження JSON, що містить лише ProjectId та SiteId.

Як ти гадаєш?



@RoryHunter У цьому посиланні є якась цікава дискусія, але нічого, що усуває мою невизначеність. Мені особливо подобається, що у прийнятій відповіді зазначено "Ви зрозуміли правильно". а 2-е місце (хоч і з великим відривом) відповідає "Простіше кажучи, ви робите це повністю назад".
Джеймі Іде

Ваш перший варіант прекрасний, хоча я б використовував PUT замість POST, оскільки клієнт контролює особу, яка додається до колекції. Ваша перша стурбованість варіантом 2 повністю залежить від вас, якщо ви не хочете нових сайтів, не кидайте винятків, але поверніть один із 4xx-кодів. Ваша друга турбота - ні тут, ні там. Ви все одно не повинні публікувати весь веб-сайт, якщо ви не допускаєте доповнень. Додавання існуючого сайту має мати ідентифікатор лише під час зміни сайту, але лише колекцію "ProjectSite" (навіть якщо ви не створите для нього окремого ресурсу).
Мар'ян Венема

Відповіді:


14

POST - дієслово "додавати", а також дієслово "обробляти". PUT - дієслово "create / update" (для відомих ідентифікаторів), і майже виглядає як правильний вибір, тому що повний цільовий URI відомий. projectIdі siteIdвже існують, тож вам не потрібно "POST на колекцію", щоб створити новий ідентифікатор.

Проблема з PUT полягає в тому, що він вимагає, щоб тіло було представлення ресурсу, який ви PUTING. Але тут наміром є додавання до ресурсу колекції "проект / сайти", а не оновлення ресурсу Сайту.

Що робити, якщо хтось ПОДАЄ повне представлення наявного Сайту JSON? Чи слід оновити колекцію та оновити об’єкт? Ви можете це підтримати, але це здається, що це не є наміром. Як ти сказав,

єдині мені потрібні дані ProjectId та SiteId

Швидше я б спробував розмістити siteIdколекцію до колекції і покластися на "додавання" та "процес" характеру POST:

POST myapi / Проекти / {projectId} / сайти

{'id': '...'}

Оскільки ви змінюєте ресурс колекції сайтів, а не ресурс Сайту , це потрібний URI. POST може знати "додавання / обробку" та додавання елемента з цим ідентифікатором до колекції сайтів проекту.

Це все ще залишає двері відкритими для створення абсолютно нових сайтів для проекту, розбиваючи JSON і опускаючи ідентифікатор. "Без ідентифікатора" == "створити з нуля". Але якщо URI колекції отримує ідентифікатор і нічого іншого, то цілком зрозуміло, що має відбутися.

Цікаве запитання. :)


Я вірю, що вважаю, що POST призначений для створення, а PUT - для оновлення, але ваш висновок - це те, де я закінчився вчора. Приємно те, що завдяки маршрутизації атрибутів у веб-API я маю код у контролері ProjectSites, тому код добре організований.
Джеймі Іде

Я думаю , що визначення причин ви повинні використовувати POSTзамість PUTабо в PATCHтому , що ви не маєте весь Siteоб'єкт , щоб помістити в sitesресурс. У вас є лише ідентифікатор, який вимагає його обробки, щоб додати його до колекції.
розчавити

4

Ми використовуємо Patchметод для подібних речей. Що ви хочете зробити - це змінити існуючий проект, щоб додати його до нього.

Тож щось подібне спрацювало б

PATCH myapi/projects/{id} 

з об'єктом сайтів (сайтів) як JSON / JSONArray в органі запиту.

Таким чином, ви можете використовувати одну і ту ж URL-адресу для зміни різних частин Проекту, якщо вам потрібно - ваш код при реалізації повинен бути досить розумним, щоб обробляти цю часткову модифікацію ресурсу.


Цікавий підхід. У мене є "багата" (тобто сильно залежна) старша модель домену, і Project особливо має безліч колекцій, що висять її. Виявлення типу юридичної особи, що знаходиться у запиті, було б викликом і не відповідало моїй прагматичній цілі.
Джеймі Іде

Чому виклик? Якщо у вас є ці обмеження, ви завжди можете використовувати JSON, який робить явне те, що він надсилає ... як {"sites": [], "other-stuff": {}}, ви можете потім розгалужити свій код, щоб дуже легко обробляти всі ці "підмайстри". Це дійсно залежить від вашої конкретної проблеми, але я все-таки рекомендую використовувати PATCH, оскільки він розроблений спеціально для подібних речей.
хуан

Мінуси, які я бачу, такі: 1) API не повідомляє прямо, які колекції дозволяють змінювати; 2) не може використовувати прив'язку параметрів Web API; 3) великий перемикач або оператор if.
Джеймі Іде

Я ніколи не бачив методу виправлення, який використовував ніде більше
NimChimpsky

Чи не PATCHочікуєте також, що тут буде передано повне ціле як його значення, а не ідентифікатор, який вказує на якусь сутність?
розчавити
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.