RESTful API дизайн. Що я повинен повернути, якщо немає рядків?


50

На даний момент я кодую API для соціальної мережі за допомогою Slim Framework. Моє запитання: Які найкращі практики, коли в структурі json немає рядків для повернення?

Скажімо, що цей виклик / v1 / get / movies повертає 2 рядки з назв кінофільму таблиці:

[
    {"name": "Ghostbusters"},
    {"name": "Indiana Jones"}
]

Але тоді я закликаю / v1 / get / books і в цій таблиці немає рядків. Чи повинен я просто повернути порожню структуру?

[
]

... чи краще було б повідомлення та код помилки?

[
    "errors": {
        "message": "no matches found",
        "code": 134
    }
]

Яка краща практика? (API буде використовуватися в додатках для iOS та Android) Дякуємо!


3
Мені це здається питанням, чи нуль насправді є сумою.
хустка

16
Ваш приклад зламаний. Ви не можете мати об’єкти json з повторюваними ключами. Що ви шукаєте, це масив, тобто[{"name": "..."}, {"name":"..."}]
Мартін Вікман

@MartinWickman Вибачте за це, я просто виправив це.
Андрес СК

8
@andufo, насправді, ти не ...
avakar

25
Якщо ваша програма призначена як RESTful, тоді чому дієслово / метод "отримати" частину вашого URI кінцевої точки?
user50849

Відповіді:


46

Зазвичай я б повертав кількість записів у результаті як метадані. Я не впевнений, що це нормальна практика REST, але це не так багато додаткових даних, і це дуже точно. Зазвичай існує пагинація для багатьох сервісів, одразу повертати величезний набір результатів недоцільно. Особисто мені дратується, коли є пагинація для невеликих наборів результатів. Якщо вона порожня, поверніться number_of_records : 0та книги як порожній список / масив books : [].

{
    meta: {
        number_of_records : 2,
        records_per_page : 10,
        page : 0
    },
    books : [
        {id:1},
        {id:27}
    ]
}

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

При роботі з пагинацією завжди пам’ятайте про можливість змісту вмісту чи замовлення. Начебто, перший запит приходить, 24 результати, ви повертаєтесь першими 10. Після цього вставляється "нова книга", і тепер у вас є 25 результатів, але з оригінальним запитом вона буде замовлена ​​на 10-му місці. Коли перший користувач запитує другу сторінку, він не отримає "нову книгу". Існують способи вирішення таких проблем, як надання "ідентифікатора запиту", який слід надсилати за допомогою наступних дзвінків API, а потім повернення наступної сторінки зі "старого" набору результатів, який слід якось зберігати і прив'язувати до "ідентифікатора запиту". Альтернативно - додати поле типу "список результатів змінено з першого запиту".

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

Якщо у вас занадто багато даних для обробки одразу , розгляньте можливість повернення "списку ідентифікаторів" з усіма результатами та деталями для деякого фрагменту цього списку та вкажіть API API multi_get / get_by_id_list для ресурсу.


1
Ага, мені цікаво, чому за цю не голосують так високо, як за іншу. Мені це подобається більше, тому що ви даєте і порожній список (який повинен був бути списком, правда?), Який ви можете сліпо повторювати без особливих умов, але також метадані вважаються способом сказати: "Ні, ми не стали" t помилка помилки для вас, насправді було 0 результатів ".
Ізката

1
-1, оскільки booksпараметр є об'єктом, але "книги" мають на увазі більше одного, а більше одного передбачає масив. Метадані круті, і все, але в кінцевому рахунку я б очікував, що колекція книг буде масивом книжкових об'єктів; якщо немає книг, просто дайте мені порожній масив
Чарльз Спрейберрі

9
Проблема в цьому полягає в тому, що додавання "number_of_records" не дає більше інформації, це просто додає надмірності та збільшує складність. Щоб повідомити про помилку, поверніть відповідний http-код + щось у тілі.
Мартін Вікман

1
Книги @cspray у списку, як вказав Ізката, мій друкарський помилок.
grizwako

2
@MartinWickman Я не хотів забруднювати оригінальну відповідь додатковими метаданими, але, на моєму досвіді, багато сервісів не повертають усі дані одразу, але "болісно".
grizwako

105

Ваш приклад зламаний. У вас не повинно бути об’єктів json з повторюваними ключами. Що ви шукаєте, це масив із об’єктами фільму, як це:

 [
    {"name": "movie1"}, 
    {"name": "movie2"}
 ]

Цей підхід також відповідає на ваше запитання. Ви повинні повернути порожній масив, коли запит не відповідає:

[]

З іншого боку, якщо ви намагаєтеся отримати певний ресурс фільму, GET api/movie/34і цей фільм не існує, поверніть 404 із відповідним повідомленням про помилку (закодованим json) у тілі


1
+1 Це дійсний JSON відповідно до json_xs.
l0b0

15

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

Отже, коли у вас є записи, ви б поверталися:

    [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]

І коли у вас немає записів, ви б поверталися:

    [

    ]

14

Якщо ви успішно виконуєте операцію, але вона не має нічого повертати, наприклад, порожня карта {}чи порожній масив, []я б хотів відповісти кодом відповіді 204, ось уривок із специфікації визначення коду статусу HTTP :

Сервер виконав цей запит, але йому не потрібно повертати тіло об'єкта і, можливо, захоче повернути оновлену інформацію. Відповідь МОЖЕ включати нову або оновлену метейнформацію у вигляді заголовків сутностей, які, якщо вони є, ОБОВ'ЯЗКОВО бути пов'язані із запитаним варіантом

Якщо клієнт є користувальницьким агентом, він НЕ повинен змінювати свій вид документа на той, що спричинив надсилання запиту. Ця відповідь в першу чергу призначена для того, щоб дозволити вводити дії, не проводячи змін у активному перегляді активного документа агента користувача, хоча будь-яка нова або оновлена ​​метеоформація ДОЛЖНА застосовуватися до документа, який наразі знаходиться в активному вікні агента користувача.

Відповідь 204 НЕ МОЖЕ включати тіло повідомлення і, таким чином, завжди закінчується першим порожнім рядком після полів заголовка.

По суті, я рекомендую використовувати 204 в програмах RESTful через HTTP, коли повернути нічого немає.


4
Я погоджуюся з коментарем @ avakar щодо іншої відповіді тут. Якщо клієнт намагається отримати доступ до / v1 / get / movies / 1, він повинен повернути 404, якщо немає фільмів, ідентифікованих за допомогою 1. Просто / v1 / get / фільми повинні повернути 200, навіть якщо фільму немає. Але 204 не підходить, оскільки призначений для введення дій.
име96

7
Ще одна проблема цього рішення полягає в тому, що для клієнта зазвичай потрібен спеціальний код: Якщо відповідь є порожнім списком, він може бути проаналізований як JSON так само, як і звичайна відповідь. Якщо відповідь порожнє тіло, аналізатор JSON, швидше за все, поскаржиться (оскільки документ emtpy недійсний JSON), тому клієнту потрібен додатковий код для перевірки HTTP 204 та пропуску розбору.
sleske

7
Я вважаю, що це неправильне прочитання наміру 204. 204, схоже, призначене не для операцій, які очікували вмісту і не знайшли жодного, а для операцій, які були успішними та не мали наміру повернутись . З Вікіпедії: "Сервер успішно обробив запит, але не повертає жодного вмісту. Зазвичай використовується як відповідь на успішний запит на видалення."
XML

10

Проведено розумну кількість роботи над створенням стандартизованого формату API JSON .

Дотримання принципів у цій специфікації означає, що всі повернені ресурси повинні бути фактично "колекціями" (навіть якщо включений лише один ресурс). Це означає, що ваш дзвінок /v1/get/moviesповернеться:

{
    "movies": [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]
}

Ваш виклик /v1/get/books(який повертає нульові ресурси) повернеться:

{
    "books": []
}

5

Для вашого конкретного прикладу я рекомендую / v1 / get / books повертати HTTP 200 з порожнім масивом.

Якщо я читаю правильно вашу публікацію, ваш API має намір збирати книги. Метафорично кажучи, у вас є полиця для книг, стелаж для DVD для фільмів та, можливо, інші контейнери, про які ви тут не згадували. Оскільки ви збираєтесь збирати книги, / v1 / get / books - це ваша книжкова полиця. Це означає, що у вашому конкретному прикладі є дійсний ресурс - список книг - який, як правило, порожній.

Причина, в якій я не пропоную повернути HTTP 404, полягає в тому, що полиця все ще є. Наразі книг на ній немає, але це все-таки книжкова полиця. Якщо б це було не книжкова полиця -якщо API не мають наміру збирати книги для приклад- тоді HTTP 404 буде доречно. Але оскільки там є ресурс, ви не повинні сигналізувати про відсутність такого, що це робить HTTP 404. Тому я стверджую, що 200 з порожнім масивом (що означає колекцію) є більш підходящим.

Причина, по якій я не пропоную повернути HTTP 204, полягає в тому, що це підказує, що "Без вмісту" є звичайним станом речей: виконання цієї дії на цьому ресурсі зазвичай нічого не призведе. Ось чому зазвичай використовується як відповідь на DELETE-запити, наприклад: природа видалення загалом означає, що повернути нічого не залишається. Випадок подібний, коли він використовується для відповіді на запити із заголовками родини If-Modified: ви хотіли вмісту лише у тому випадку, якщо ресурс змінився, але його немає, тому я не дам вам жодного вмісту.

Але я стверджую, що для отримання порожньої, але дійсної колекції, HTTP 204 не має сенсу. Якщо в колекції були елементи, то правильне представлення було б масивом цих даних. Тому, коли даних там немає (але колекція є дійсною), правильне представлення - це порожній масив.


5

Ви дійсно повинні робити лише одну з двох речей

Або поверніть 200 (OK)код статусу та порожній масив у тілі.

Або повернути 204 (NO CONTENT)код статусу та НІ відповідь.

Мені варіант 2 видається більш технічно правильним і відповідає принципам REST та HTTP.

Однак варіант 1 видається більш ефективним для клієнта - оскільки клієнту не потрібна додаткова логіка для розмежування двох кодів (успішного) статусу. Оскільки він знає, що він завжди отримуватиме масив, він просто повинен перевірити, чи не отримав жоден, один чи багато елементів та обробити його належним чином


3

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


3

Перше, що слід врахувати, оскільки ви будуєте API RESTful - це повернути відповідний код відповіді. І більш відповідний код відповіді для повідомлення про те, що запит проходив нормально, але запитуваний ресурс наразі недоступний - це поважна 404.

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

Тут немає «найкращої практики», обидва ваші приклади є довільними, просто виберіть один і будьте послідовні . Розробники ненавидять сюрпризи, якщо /v1/get/moviesповернення, {}коли немає фільмів, тоді ми очікуємо /v1/get/actorsповернення, {}коли немає акторів.


1
Повернення 404 дійсно - це правильно зробити, але, на жаль, ніхто насправді цього не робить - я в тому числі.
RibaldEddie

1
якщо у вас є складні відповіді, і лише їх частини порожні, повернення 404 збентежить користувача.
devnull

5
Я не погодився б із повідомленням 404. 404 Я би трактував як "ресурс не існує" і хвилююся, якщо я щось не так з моєю URL-адресою чи іншим чином. Якщо я запитаю перелік фільмів і отримаю 404, я б подумав, що це зовсім не кіноресурс. "204 Без вмісту" може бути більш підходящим.
thorsten müller

8
Гаразд, річ "без тіла" вбила б це. Але: "Клас 4xx коду статусу призначений для випадків, коли клієнт, здається, помилився." Але помилки на стороні клієнта не було. Таким чином, 404 дає неправильну інформацію. Або надішліть 204 без тіла, або скажіть, що це нормально, і надішліть порожній список.
thorsten müller

9
Ви запитуєте список книг, повернення 404 означатиме, що список не існує, не те, що він порожній. Повернення 200 разом із порожнім списком здається мені єдиним розумним варіантом.
авакар

1

Я не думаю, що правильна відповідь є тією, що позначена.

Відповідь, надана дев'ятою, повинна бути найкращою за справжнім сценарієм REST. Відповідь тіла має бути порожньою, а код статусу http: 204; ресурс існує, але на той момент він не має "вмісту": порожній.

REST HTTP_Status_Codes


1

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

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

Була пропозиція повернути статус 204 + порожнє тіло. Це означає , що ви змушуєте кожен одного клієнта стану процесу 204 правильно. Більше того, ви змушуєте їх обробляти відповіді, що не відповідають JSON! Я сподіваюся, що всі розуміють, що лише тому, що на запит отримано відповідь, це не означає, що відповідь надійшла від сервера, коли використовується http, а просто перевірка того, що відповідь JSON обробляє багато з цих випадків.


0

Я б "Це залежить".

Якщо нуль - розумний результат, поверніть порожній список. Наприклад, якщо ви хочете, щоб усіх співробітників назвали "bob", де "none" є цілком розумним результатом. Якщо це не очікуваний результат, поверніть помилку. Наприклад, отримання історичного списку адрес вулиці для людини, яку ви наймаєте. Вони повинні жити десь, тому результат, мабуть, не є помилкою, а не просто нормальним станом.

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


0
  • Перш за все, якщо getу вашій URL-адресі немає ВІДБУДОВОГО, GET має на увазі метод HTTP.
  • Якщо ви запитуєте колекцію, як-от GET api/moviesповернути а 200 OKз порожнім масивом [].
  • Якщо ви запитуєте певний фільм, як-от GET api/movies/1(де 1ідентифікатор), і він не існує, поверніть а 404 Not Found.

Чому? Ви запитуєте ресурси . Коли ви запитуєте колекцію, сам ресурс (колекція) існує. Отже, a 404- це неправильно. Але якщо ви запитуєте певний фільм, і він не існує, запитуваний ресурс не існує, і ви повинні повернути 404.


-2

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

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