Чи може API REST повертати кілька ресурсів як один єдиний складний ресурс?


10

Я зараз розробляю API REST, і наразі у мене виникає така проблема:

  • Fooє першим ресурсом. Операції CRUD можна застосувати через /foo/URI.
  • Barє другим ресурсом. Операції CRUD можна застосувати через /bar/URI.
  • Кожен Fooасоціюється з нулем або одним Bar. Причина, по якій я не Barставлюсь до субресурсу, Fooполягає в тому, що один і той же Barекземпляр може бути спільним між mutiple Foos. Тому я зрозумів, що краще отримати доступ до нього через незалежний URI, а не через /foo/[id]/bar.

Моя проблема полягає в тому, що у значній кількості випадків клієнти, які запитують про Fooекземпляр, також зацікавлені в асоційованому Barекземплярі. В даний час це означає, що вони повинні виконувати два запити замість одного. Я хочу представити спосіб, який дозволяє отримувати обидва об'єкти одним запитом, але я не знаю, як моделювати API для цього. Що я придумав поки що:

  • Я міг би ввести параметр запиту , схожий на цей: /foo/[id]?include_bar=true. Проблема такого підходу полягає в тому, що представлення ресурсів (наприклад, структура JSON) відповіді повинно виглядати інакше (наприклад, контейнер, такий як { foo: ..., bar: ... }просто серіалізований Foo), що робить Fooкінцеву точку ресурсу "неоднорідною". Я не думаю, що це добре. Під час запитів /fooклієнти повинні завжди отримувати однакове представлення ресурсів (структуру), незалежно від параметрів запиту.
  • Інша ідея полягає у запровадженні нової кінцевої точки лише для читання, наприклад /fooandbar/[foo-id]. У цьому випадку повернути таке представлення не проблема { foo: ..., bar: ... }, адже тоді це лише "офіційне" представлення fooandbarресурсу. Однак я не знаю, чи така кінцева точка-помічник справді ВІДПОВІДНА (саме тому я написав "можна" у назві питання. Звичайно, це технічно можливо, але я не знаю, чи це гарна ідея).

Як ти гадаєш? Чи є інші можливості?


Який термін стосунки між Foo та Bar? Чи можете ви сказати, що Бар - це батько Фоо?
Натан Меррілл

Не Barможе існувати без асоціації з a Foo. Однак, як я писав вище, цілком можливо, що множини Foos поділяють одне і те ж Bar. Слід створити Fooбез Barасоційованого, тому я не думаю, що до цього Barслід ставитися як до батьківського.
ceran

1
Я думаю, у вас виникають деякі проблеми, які виникли у мене, переклавши безпосередньо відносини моделі домену в URI та прирівнюючи ресурси до об'єктів домену . Це може зацікавити, що API REST повинен керуватися гіпертекстом . Особлива увага до 4-го пункту
Laiv

Відповіді:


6

Рівень 3 REST API буде повертати вам , Fooа також посилання , що вказує пов'язаними з цим Bar.

GET /foo/123
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456"/>
</foo>

Потім ви можете додати у свій API функцію "розгортання", яка дозволяє навігацію посилань;

GET /foo/123?drilldown=bar
<foo id="123">
  ..foo stuff..
  <link rel="bar" uri="/bar/456">
    <bar id="456">
      ..bar stuff...
    </bar>
  </link>
</foo>

Функція розгортання буде сидіти перед API та перехоплювати відповіді. Це дозволило б зробити детальні дзвінки і заповнити дані, перш ніж повертати відповідь абоненту.

Це досить поширена річ на рівні 3 REST, оскільки це значно зменшує балаканість клієнта / сервера через повільний http. Компанія, над якою працюю, виробляє API REST рівня 3 саме з цією функцією.

Оновлення: для чого варто, ось як це може виглядати в JSON. Ось так структурував би наш API. Зауважте, що ви можете вкладати свої свердловини, щоб перетягувати посилання тощо.

GET /foo/123?drilldown=bar

{
  "self": {
    "type": "thing.foo",
    "uri": "/foo/123=?drilldown=bar",
    "href": "http://localhost/api/foo/123?drilldown=bar"
  },
  "links": [
    {
      "rel": "bar",
      "rev": "foo",
      "type": "thing.bar",
      "uri": "/bar/456",
      "href": "http://localhost/api/bar/456"
    }
  ],
  "_bar": [
    {
      "self": {
        "type": "thing.bar",
        "uri": "/bar/456",
        "href": "http://localhost/api/bar/456"
      },
      "links": [
        {
          ..other link..
        },
        {
          ..other link..
        }
      ]
    }
  ]
}

Цікаво, що я вже використовую гіпермедіатичні посилання / елементи управління, щоб зняти щільне з’єднання з URI, але я не замислювався над ідеєю "розгортання", яка здається дуже перспективною. Як могло виглядати представлення JSON? На даний момент кожне представлення моїх ресурсів JSON містить linksмасив, кожен запис - це об'єкт посилання з a relі uriполем (подібно до прикладу xml). Чи слід просто додати третє поле до кожного об’єкта посилання (наприклад data)? Чи є якийсь стандарт?
ceran

Свердлування насправді не є функцією відпочинку, тому немає ніяких стандартів (принаймні, що я знаю).
Qwerky

Існують деякі запропоновані стандарти, такі як stateless.co/hal_specification.html, які я використовую в наших програмах. Це дуже близько до вашого прикладу.
Піт Кіркхем

4

Якщо 95% всіх запитів хочуть Foo, а також Bar, то просто повернути його всередину від Fooоб'єкта , коли ви запитуєте Foo. Просто додайте властивість bar(або який-небудь інший термін для відносини) і поставте Barтуди об’єкт. Якщо відносини не існують, використовуйте null.

Я думаю, ти це передумуєш :)


Я не повинен був придумати це число (95%), це була помилка, вибачте. Що я хотів сказати, це те, що значна частина запитів зацікавлена ​​в обох ресурсах одночасно. Але все ще є відповідна кількість запитів, які цікавлять лише вас Foo, і оскільки кожен Barмає досить величезну пам’ять (приблизно 3x-4x розмір Foo), я не хочу повертати файл, Barякщо клієнт не вимагає цього прямо.
ceran

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