API REST - Чи повинен API повертати вкладені JSON об'єкти?


38

Якщо мова заходить про API JSON, чи корисна практика вирівняти відповіді та уникати вкладених JSON-об'єктів?

Як приклад, можна сказати, що у нас є API, схожий на IMDb, але для відеоігор. Є кілька об'єктів, ігри, платформи, ESRBRating та GamePlatformMap, які відображають ігри та платформи.

Скажімо, ви вимагаєте / game / 1, яка отримує гру з ідентифікатором 1, і вона повертає ігровий об'єкт з платформами та esrbRating вкладеними.

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"id":1,"name":"Xbox"},
    {"id":2,"name":"Playstation"}
  ],
  "esrbRating": {
    "id": 1,
    "code": "E",
    "name": "Everyone"
  }
}

Якщо ви використовуєте щось на зразок JPA / Hibernate, це може зробити це автоматично для вас, якщо для нього встановлено FETCH.EAGER.

Інший варіант - просто API та додавання більшої кількості кінцевих точок.

У тому випадку, коли / game / 1 запитується, просто повертається ігровий об’єкт.

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
}

Якщо ви хочете, щоб платформи та / або ESRBRating вам доведеться зателефонувати наступним чином:

/ гра / 1 / платформа / гра / 1 / esrb

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

Була одна остання думка, що я мав, де ти повернеш щось подібне.

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": ["Xbox","Playstation"]
}

Однак це передбачає, що їм не потрібні ідентифікатори або будь-яка інша інформація, яка може бути пов’язана з цими об'єктами платформи.

Я взагалі запитую, який найкращий спосіб структурувати свої об’єкти JSON, повернені з вашого API. Якщо ви намагаєтесь залишатися якомога ближче до своїх організацій, або добре використовувати об’єкти домену або об’єкти передачі даних? Я розумію, що методи матимуть компроміси, або більше роботи над рівнем доступу до даних, або більше роботи для клієнта.

Я також хотів би почути відповідь, пов’язаний із використанням Spring MVC як резервної технології для API, з JPA / Hibernate або MyBatis для постійності.


6
Які заперечення, якщо такі є, у вас повертаються вбудовані об’єкти? Повернення вбудованих об'єктів окремо з різних кінцевих точок стане досить проклятим (не кажучи вже про повільне).
Роберт Харві

1
Особисто я не заперечую проти цього. Я просто не знаю, що вважається найкращою практикою. Колега стверджує, що робота з вбудованими об'єктами в AngularJS не є прямою, і, врешті-решт, я хотів би, щоб програма Ember of AngularJS споживала API. Я не знаю достатньо про Кутовий або Ембер, щоб знати, чи матиме це вплив чи ні.
greyfox

3
Відповідь залежатиме від того, чи хочете ви повернути об’єкти домену, об'єкти DTO, ViewModel або KitchenSink. Який об’єкт ви повертаєте, швидше за все, буде визначатися те, що потрібно вашій програмі та як поводиться цей об’єкт в Інтернеті. Приклад: якщо ви намагаєтеся заповнити веб-сторінку даними з рахунку-фактури, дуже ймовірно, що ви збираєтесь повернути об’єкт, що містить усе необхідне (якщо ви не плануєте AJAXing у позиціях чи щось подібне).
Роберт Харві

У цьому випадку, коли ви запитуєте гру, ви, ймовірно, захочете знати жанри, платформи та ESRBRating. Що має сенс. З точки зору дизайну з точки зору Java, чи рекомендуєте ви мати пакет Entity, який містить елементи JPA, а потім пакет доменів, який бізнес-об'єкти / DTO повертається користувачеві?
greyfox

1
Дзвінки на сервер дорогі. API, який вимагає від вас надсилання даних за допомогою декількох викликів, буде повільніше, ніж API, який дозволяє отримувати все за один виклик, часто навіть тоді, коли останній повертає непотрібну інформацію.
Gort the Robot

Відповіді:


11

Ще одна альтернатива (з використанням HATEOAS). Це просто, в основному на практиці ви додаєте тег посилань у json залежно від використання HATEOAS.

http://api.example.com/games/1:

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"_self": "http://api.example.com/games/1/platforms/53", "name": "Playstation"},
    {"_self": "http://api.example.com/games/1/platforms/34", "name": "Xbox"},
  ]
}

http://api.example.com/games/1/platforms/34:

{
  "id": 34,
  "title": "Xbox",
  "publisher": "Microsoft",
  "releaseDate": "2015-01-01",
  "testReport": "http://api.example.com/games/1/platforms/34/reports/84848.pdf",
  "forms": [
    {"type": "edit", "fields: [] },
  ]
}

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

Технічна реалізація може містити кешування. Ви можете кешувати посилання на платформи та назви в ігровому об’єкті та надсилати їх миттєво, не завантажуючи api платформ взагалі. Тоді, коли потрібно, ви можете завантажити його.

Ви бачите, наприклад, що я додав інформацію про форму. Я зробив це, щоб показати вам, що в детальному json-об'єкті може бути набагато більше інформації, ніж ви хотіли б навіть завантажувати в список ігор.


Я не думаю, що це технічно HATEOS, оскільки немає держави.
RibaldEddie

Так, не впевнений, яке саме слово в цьому процесі. HATEOS взагалі використовується для з'єднання в API відпочинку, але я згоден, це також має відношення до держави. Хоча ідея реалізації буде однаковою. Тут ви бачите трохи більше про те, як це можна використати на прикладі: stormpath.com/blog/linking-and-resource-expansion-rest-api-tips
Люк Франкен

Хоча це гарна ідея!
RibaldEddie

1
Якщо ви розробляєте API, у якому є згуртованість між клієнтом і самим api (скажімо, внутрішнім api), може бути більш доцільним повернути вкладений (або сплющений) відповідь, а не надавати посилання на інший ресурс, що означає більше запитів API які можуть бути небажаними.
Бруно

@bruno так, але з обмеженням: у великих системах ви не можете або не хочете надавати всі пов'язані об'єкти в повному обсязі. Поля, які ви включаєте за замовчуванням, є довільними, ви можете вибрати їх залежно від використання api. Тож у цьому випадку у вас можуть бути платформи із сотнями полів, у випадку використання показано поле вибору для вибору платформи. Тоді є сенс включити назву платформи, але вона не потребує, наприклад, фінансових деталей платформи.
Люк Франкен

16

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


11
Це зовсім не корисно. Сам ОП знав, "це залежить, і кожен підхід має плюси і мінуси". Вам слід пояснити, від чого це залежить, або принаймні навести приклад.
Пратік Сінгал

5

Я другий підхід, представлений тут https://www.slideshare.net/stormpath/rest-jsonapis

Коротше кажучи, включіть вкладений ресурс як посилання на батьківський ресурс, тим часом надайте параметр розширення у батьківській кінцевій точці.

На мою думку, це спосіб, який у більшості випадків є ефективним та гнучким.


2
Мені подобається такий підхід. Для всіх, хто цікавиться, це починається з SLIDE 57 у слайд-шоу, що пов’язаний.
Адам Плочер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.