Який найкращий спосіб повернути масив як відповідь у API RESTful?


40

Припустимо, у нас є такі ресурси,

book:
    type: object
    properties:
        author: {type: string}
        isbn: {type: string}
        title: {type: string}

books:
    type: array
    items: book

Отже, коли хтось робить GETна книжковому ресурсі, ми б поверталися наступним

[{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
 {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]

Я чув від когось із роботи, що рекомендована практика REST - це завжди повертати відповіді як об’єкти JSON, що означатиме, що наша схема booksвиглядатиме так,

books:
    type: object
    properties:
        list:
            type: array
            items: book

Отже, зараз відповідь виглядатиме так:

{
    "list": [{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
             {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]
}

Яка з них є найкращою практикою REST?


1
JSON RESTful? Ви обов'язково повинні повернути HTML?
Еван

3
@Ewan: корисне навантаження не має значення. Саме для цього призначені типи MIME.
Роберт Харві

1
Не найкращі практики для REST. REST створений з HATEOAS, що означає відкриття вашого API. Знайдіть HAL або JSON-LD.
Флоріан Маргаїн

Json-ld: повільно просувається до WCF
Еван

З того, що я читаю, що обгортає масиви JSON всередині об’єкта, є захисним заходом проти повідомлення про вразливість у старих браузерах - haacked.com/archive/2009/06/25/json-hijacking.aspx . Це, здається, було зафіксовано в сучасних броуерах сьогодні. Краще безпечніше, ніж шкода, мабуть ..
Gishu

Відповіді:


35

На практиці другий варіант - найкраща практика. Причина цього полягає в тому, що ви взагалі не можете розширити ресурс, коли просто повернете масив.

Наприклад: Якщо вам потрібно додати кількість всіх записів, ви вже виконали лише підхід до масиву.

Якщо це відбувається в одному списку api, тоді ви хочете підтримувати його послідовно, тому зробіть все об'єктом, тоді ваш api стає більш послідовним і простішим у використанні для розробників.

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

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


3
+1 для "реальності щодо даних" (і при цьому все ще визнаєш, що для REST існує більш технічне, точніше визначення).
кинув

8

І те й інше

[{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},{"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]

і

{
    "list": [{"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
         {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}]
}

дійсні Json. Я не думаю, що вам слід додавати "список", якщо він не потрібен, це може бути навіть заплутано, оскільки те, що йде за ним, - це масив, а не список.

Краща практика REST? API повинен дати належну відповідь на те, що встановлено в заголовку Accept, а також хорошу документацію.


7

Причина, по якій ви відповідаєте JSON, відповідає тому, що JSON є стандартом дефакто; будь-яка мова з аналізатором JSON може тривіально розібрати його, і якщо ви використовуєте JavaScript, вам навіть не потрібен аналізатор, оскільки JavaScript розуміє його на самому собі.

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

REST не має нічого спільного з вашою схемою JSON. Будь-яка схема є прийнятною з точки зору REST.


9
Чи відповідає це на питання? Я читав це як "Чи слід використовувати масив json або об'єкт json як корінь?". Обидва можуть бути розібрані з парсерами json, тому ваша відповідь не допомагає їм вирішити.
CodesInChaos

Тоді це не має значення. Я оновив свою відповідь.
Роберт Харві

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

...and if you're using JavaScript, you don't even need a parser since JavaScript understands it natively.Ну так і ні. JSON - це підмножина JavaScript, але виклик evalзамість використання аналізатора негайно робить вас вразливим до "JSON", який містить шкідливий код, і синтаксичний аналіз, швидше за все, є більш ефективним, ніж evalбудь-який спосіб.
Doval

5

Словник з єдиним безглуздим ключем "список" та значенням масиву є безглуздим - натомість поверніть масив.

Якщо одна і та ж служба може повернути книги, компакт-диски або DVD-диски, ви можете повернути словник з клавішею "книги" та значенням масиву. Можливо, є ще одна клавіша "DVD" з масивом DVD. Наприклад, якщо клієнт може запитати перелік усіх своїх покупок.

Якщо ви впевнені, що відповідь буде трактуватися лише як перелік книг (якщо в запиті сказано "дайте мені список книг"), тоді просто масив буде нормальним.


5

Другий варіант також є кращим методом з міркувань безпеки. У старих браузерах є вразливість безпеки, яка дозволяє іншим кодом javascript на веб-сторінці красти ваші дані, якщо вони повертаються як масив JSON. Тож історично найкращою практикою було не повертати масиви JSON. Насправді були деякі рамки, функція "json-ify" вибирає варіант 2 за замовчуванням, коли ви переходите в масив.

https://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk

http://ejohn.org/blog/re-securing-json/


1

обидва є json і дотримуються REST. Я би зробив відповідь більш описовою, у вашому випадку список змін до книг. Або щось подібне:

{ "responceObject" : {

   results : 2,

    "Books": [
        {"author": "Dan Brown", "isbn": "123456", "title": "Digital Fortress"},
        {"author": "JK Rowling", "isbn": "234567", "title": "Harry Potter and the Chamber of Secrets"}
    ]

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