Чи має бути "Без результатів" помилка у відповіді на RESTful?


52

Я опишу приклад:
я починаю робити API для випічки. API дозволить людям здійснювати пошук у каталозі продуктів для випічки, таких як домашнє м'ясне печиво з шоколадного печива, використовуючи api.examplebakery.com/search?q=......

Хтось використовує це для пошуку продукту з назвою pineapple-banana flavoured cookiesі очевидно не знайде жодного результату.

Чи слід повернути це як помилку? Пошук не провалився, API здійснив пошук і успішно дійшов висновку, що файлів cookie не вдалося знайти. API не повинен повертатися 404, оскільки API був дійсно знайдений.




3
@gnat: Це не дублікат, оскільки інше питання стосується конкретного ресурсу, а не запиту проти кількох ресурсів.
Грег Бургхардт

7
Аналогічно, припустимо, у вас є функція, яка повертає масив об'єктів. Якщо немає об'єктів, що відповідають конкретному випадку використання, ви б скоріше функціонували через виняток або повертали порожній масив?
Кевін - Відновити Моніку

2
@AakashM Повернення HTTP-204 до GET-запиту є досить незвичним, я знаю, що я його ніде не бачив. Наскільки мені відомо, HTTP-204 зазвичай використовується як відповідь при зміні ресурсу на сервері, наприклад, POST / PUT / DELETE запити.
Radu Murzea

Відповіді:


122

Коли є результати, результатом є список (JSON, заснований на вашому коментарі). Для запитів без результатів результат повинен бути абсолютно однаковим. У простому списку є 0 елементів.

Тож якщо ваша відповідь зазвичай така:

{
    "results": [
        {
            "name": "Pancakes",
            ....
        },
        {
            "name": "French Fries",
            ....
        }
    ]
}

Тоді для запиту з 0 результатами має бути таке:

{
    "results": []
}

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

Статус HTTP повинен бути таким же, як і коли є результати - 200 OK.

204 No Contentможе також здатися варіантом, але це не тому, що ви насправді повертаєте "вміст" - порожній список. Якщо ви вважаєте, що порожній список не вважається "вмістом", що робити, якщо ви зміните відповідь, щоб запропонувати правописні пропозиції? Ядром відповіді все одно буде порожній список, але зараз ще більше "змісту".

Для отримання більш корисної інформації про коди статусу HTTP, jpmc26 їх відповідь варто прочитати.


9
Це такий самий вид мислення, як і нульовий предметний малюнок . Помилки та нуль - не єдиний спосіб сказати, що тут нічого немає. Іноді хочеться тихо висловити своє. Таким чином клієнтам не потрібно тестувати нічого.
candied_orange

54
Я заперечую, що повернення 204 є недоцільним, оскільки ви повертаєте вміст. Просто вміст не має результатів, що відрізняється від того, щоб взагалі не повертати вміст.
TMN

9
@TMN погодився - 204 не підходить для "немає результатів". Ваш запит завжди повинен повертати масив із результатами всередині масиву. Якщо результатів немає, клієнт впорається з цим природно. Якщо клієнт хоче показати спеціальний текст ("Результатів не знайдено"), це добре. 204 слід повернути лише для кінцевої точки, яка природно не повертає результат.
JasonB

1
Ви можете використовувати 204, якщо ви повертаєте нульову серіалізацію як порожній рядок, який я відновлюю
Еван,

15
Це. Важлива річ при побудові API RESTful - це частина API, а не спокійність. Хороший API полегшує життя клієнтам / споживачам. Порожній масив легше обробляти, ніж нульові значення / винятки / коди статусу.
Гуран

37

Щоразу, коли ви приймаєте HTTP-код, вам завжди слід задавати це питання:

Що може робити / чи / повинен робити будь-який довільний клієнт із відповіддю?

  1. Чи повинен клієнт завжди трактувати відповідь як невдачу? Потім ви хочете 4xx або 5xx, залежно від того, проблема полягає у введенні клієнта чи процесах сервера.
  2. Чи повинен клієнт зробити запит десь в іншому місці? Тоді 3xx для вас.
  3. Чи зробив сервер те, що клієнт запитав (вдалося)? Це 2xx.

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

У цьому випадку клієнт запитав список результатів, який отримав фільтр з дійсної, існуючої кінцевої точки та має дозвіл на доступ до нього. Сервер зміг обробити запит і визначити відповідні дані для повернення (немає елементів), тому запит був успішним. Просто буває, що фільтр, який вони дали, відфільтрував усі результати. Сервер не залежить від того, хотів чи ні клієнт, оскільки це може бути очікуваним результатом для деяких клієнтів. Якщо це якимось чином проблема з клієнтським кодом, це обов'язок клієнта визначати, перевіряти та обробляти належним чином. Тож це однозначно 2х.

Тепер питання: "Який 2xx?" Це залежить від того, як ви плануєте відповідати серверу.

  • Ви надішлете подання порожнього списку, як описано в деяких інших відповідях ? Якщо це так, ви хочете, щоб 200. 200 означає, що сервер не мав проблем і має представлення результатів для клієнта. Це, мабуть, найзручніший спосіб відповісти для своїх споживачів, які можуть просто проаналізувати відповідь, були результати чи ні, а потім зрозуміти, як самостійно обробити порожній список.
  • 204 тут не семантично помиляється, але вам доведеться відповідати без будь-якого повідомлення . Це означає, що весь клієнтський код повинен явно перевірити наявність різних HTTP-кодів (або принаймні на відсутність тіла повідомлення) та обробляти їх окремо. Це незручно і, швидше за все, призведе до погано поводиться клієнтів.

Інші взагалі не застосовуються:

  • 201 не йдеться. Ви не створили постійних ресурсів і не повертаєте місцезнаходження до створеного ресурсу.
  • 202 не йдеться. Запит виконаний; це не обробка у фоновому режимі.
  • 203 означає, що відповідь була змінена між авторитетним сервером і клієнтом. Ваш RESTful інтерфейс є авторитетним сервером, тому це не стосується тут.
  • 205 не має сенсу. Вам не потрібен клієнт, щоб очистити або оновити що-небудь.
  • 206, схоже, призначений для повернення великого ресурсу за допомогою декількох відповідей. Він також вимагає, щоб клієнт запитував частину вмісту в заголовках (тому пагинація через рядки запиту не кваліфікується). Тут не застосовується.

Таким чином, це повинно бути або 200, або 204, і 200 швидше призведе до більш простого і надійного клієнтського коду (особливо якщо ви використовуєте послідовну структуру відповідей, що містить порожній список).


5
Був би зацікавлений у думці низовика. Я не думаю, що щось із цього навіть суперечливе.
jpmc26

2
Я не думаю, що клієнти повинні чітко перевіряти 204. Все, що їм потрібно, - це можливість обробляти об'єкт нульової відповіді. Завдання рамки HTTP - це обробляти 204, пропускаючи частину "розбору тіла". 200 із вмістом Content-Lenght 4 і нульовим знаком тіла точно так само.
Agent_L

1
@Agent_L Ви маєте рацію, що якщо сервер відповість структурою, що не відповідає нормальній відповіді (як, наприклад, розміщення nullсписку там, де зазвичай є список), ви не отримаєте переваг послідовності навіть при 200. Однак те, що я описую, використовує відповідь, що відповідає нормальній структурі і має порожній список, куди звичайно відображатиметься список результатів. 204 забирає будь-яку можливість отримати таку послідовну відповідь. Крім того, навіть у бібліотеках клієнтів HTTP, які мають функції зручності для нього, вам часто (як правило?) Потрібно робити явний виклик для розбору JSON.
jpmc26

@Agent_L Зокрема, зі списками, абоненти часто можуть просто дозволити своєму коду нормально працювати над порожнім списком (наприклад, циклічно перебираючи його), тоді як їм потрібна чітка перевірка для обробки іншого типу представлення.
jpmc26

16

Ні, використання 404 для позначення "ваш запит оброблено, але не було відповідностей" є жахливим, оскільки:

  • умовний потік, що базується на обробці винятків (тобто змушувати невиключний результат створювати та обробляти виняток у клієнта, який може бути неприйнятним та незручним)

  • неоднозначність між "реальною" сторінкою не знайдено, ви ввели кінцеву точку помилок

Що слід пам’ятати, це те, що клієнт завжди десериалізує повідомлення та його те, що той клієнт повертає, що важливо; не серіалізація.

Якщо клієнт повинен повернути null, використовуйте серіалізацію null. Якщо клієнт повинен повернути порожній масив, використовуйте [], якщо клієнт повинен кинути помилку на використання 500 і передати повідомлення про помилку


2
Чому сервер повинен дбати, що клієнт робить з інформацією? (PS: Я не той, хто спростував вашу відповідь).
Radu Murzea

у цьому контексті «клієнт» - це код, що працює на клієнтському пристрої, який відкриває послугу клієнтській програмі. Він повинен вміти розкривати методи обслуговування та повертати результати, як задумано службою. Вам потрібна пара клієнт-сервер, щоб спілкування взагалі функціонувало
Еван,

3
Звичайно, не використовуйте 5xx для помилок клієнта . У цьому випадку віддайте перевагу 4xx.
Кевін

1
Хоча, чи не повинен це бути "сервер", а не "клієнт" у більшості цих випадків? Це сервер, який обробляє запит і подає відповідь, клієнт просто обробляє відповідь? У такому випадку код 5xx буде добре, оскільки це помилка сервера, а не помилка клієнта?
MrWhite

2
проблема з усіма кодами помилок полягає в тому, що вони мають значення в http. 500 - єдиний код, який підходить, коли ваша служба кидає виняток
Ewan

9

Дуже гарна відповідь Евана:

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

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


так, я точно подумав, що на відповідь Евана.
Вальфрат

5

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


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

0

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

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

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

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

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