Чи повинен REST API повертати помилку 500 внутрішнього сервера, щоб вказати, що запит посилається на об'єкт, який не існує?


39

Я працюю з API REST, який знаходиться на сервері, який обробляє дані для безлічі пристроїв IoT.

Моє завдання - запросити сервер за допомогою API для збору конкретної інформації про продуктивність цих пристроїв.

В одному випадку я отримую список доступних пристроїв та їх відповідних ідентифікаторів, а потім пізніше запитую сервер для отримання більш детальної інформації за допомогою цих ідентифікаторів (GUID).

Сервер повертає 500 Internal Server Errorзапит на один з цих ідентифікаторів. У моїй заявці видається виняток, і я не бачу деталей про помилку. Якщо я більш детально вивчу відповідь з Postman , я можу побачити, що сервер повернув JSON в тіло, яке містить:

errorMessage: "This ID does not exist".

Нехтуйте тим, що сервер надав ідентифікатор для початку - це окрема проблема для розробника.

Чи повинен REST API повертати а, 500 Internal Server Errorщоб повідомити, що запит посилається на об'єкт, який не існує? На мій погляд, коди відповідей HTTP повинні суворо ставитися до статусу виклику REST, а не до внутрішньої механіки API. Я б очікував, 200 OKщо відповідь, що містить помилку та опис, буде власником відповідного API.


Мені здається, що існує різниця потенціалів у очікуванні залежно від структури REST-дзвінка.

Розглянемо наступні приклади:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

У першому випадку ідентифікатор пристрою передається у вигляді змінної GET. 404 або 500 означатиме, що шлях ( /restapi/deviceinfo) або не знайдений, або призвів до помилки сервера.

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


Ця умова, яку ви описуєте, вважається успішною чи невдалою?
Роберт Харві


@RobertHarvey Моє сподівання було, що API поверне деяку інформацію про пристрій. Сам запит мав би бути успішним, але ідентифікатор пристрою, який пропав, не повинен спричинити збій на рівні запиту.
JYelton

18
Ідентифікатор, що не існує, звучить для мене як 404. Найпоширенішою причиною 500 помилок є програмісти, що дозволяють внутрішнім виняткам підключити для хостингу сервер для обробки. Іноді бувають справді виняткові випадки, коли це відбувається, а іноді це просто ліниве програмування. Важко сказати, що тут відбувається.
Берін Лорич

9
500 внутрішніх серверів означає "Наша вина, ми щось зіпсували", і ви ніколи не повинні прагнути повернути цей статус користувачеві. Його мета полягає в основному вказувати на помилку - ваш користувач може сказати, що вони отримують 500, коли вони роблять певний запит, а потім ви можете зайти і виправити його.
berry120

Відповіді:


96

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

Відповідно до RFC 2616 , визначення коду статусу 404 є:

10.4.5 404 Не знайдено
Сервер не знайшов нічого, що відповідає запиту URI. Не вказується, чи є стан тимчасовим чи постійним. Код стану 410 (Зникло) ДОЛЖЕН використовуватись, якщо сервер через якийсь внутрішньо настроюваний механізм знає, що старий ресурс постійно недоступний і не має адреси переадресації. Цей код статусу зазвичай використовується, коли сервер не бажає виявити, чому саме в запиті відхилено, або коли інша відповідь не застосовується.


6
404 - це лише семантична відповідність, якщо ідентифікатор, який не існує, відповідає ресурсу, який отримують.
Роберт Харві

55
@ThomasOwens Запит, що не повертає результатів, повертає статус 200 і порожній масив результатів. Повідомлення 404 буде повернуто лише при визначенні конкретного ідентифікатора об'єкта, який насправді не існує.
Шон Бертон

11
@ThomasOwens: з точки зору абонента кінцева точка не є /questions, це /questions/368213. Ця кінцева точка не існує у вашому сценарії. Подумайте про це так: якщо ви робите GET на / foo / bar, і немає смужки, чому відповідь повинна бути різною, якщо / foo існує чи ні?
Брайан Оуклі

17
Правильно, це не помилка сервера, тому ми не надсилаємо 5xx. Це помилка клієнта - клієнт запитував, що щось не має, тому ми надсилаємо 4xx, зокрема 404.
bdsl

7
@ThomasOwens: How do you differentiate between a 404 meaning "the query returned no results" and a 404 meaning "the endpoint does not exist"?- 400 поганий запит.
Роберт Харві

34

Я буду використовувати ваші приклади.

http://example.com/restapi/deviceinfo?id=123

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

Якщо кінцева точка призначена для повернення одного результату , мій вибір був би 404 NOT FOUND, тому що для мене правильний синтаксис для такого роду кінцевої точки є: http://example.com/restapi/deviceinfo/123. Зазвичай я використовую параметр запиту лише для фільтрації і коли моя кінцева точка повертає масив.

http://example.com/restapi/device/123/info

Я думаю, що на це питання вже тут відповіли . POST або GET, кращим вибором здається, 404 NOT FOUNDоскільки ресурс 123не знайдено.

В обох випадках я не бачу необхідності пояснювати причину запиту. Інформація про запит та код HTTP вже пояснюють, чому.


2
Як ви відрізняєте неіснуючий ідентифікатор від неправильної URL-адреси?
Роберт Харві

2
@luizfzs, ти можеш до цього також, я не можу в цьому бачити проблеми. У деяких API, які я розробив, я вважаю за краще використовувати 204 в успішному PUT або DELETE ( як пояснено тут ) без будь-якого органу на відповідь.
Дерік

10
Чому на цьому рівні слід відрізняти неіснуючий ідентифікатор і неправильну URL-адресу? У будь-якому випадку ви все ще робите дійсний запит, що стосується HTTP. Сервер просто ... ну ... не може знайти ресурс, на який ви звертаєтесь. Неправильна URL-адреса не є неправильним запитом; це добре сформований запит про неправильну річ .
cHao

6
@cHao Оскільки, як розробник, я хочу знати, чи не працює програма, оскільки елемент не існує, або якщо я випадково вказав свій додаток на app.company.cxm / test /, а не на app.company.cxm / tst /
Патрік М

7
@PatrickM: Як розробник, ви повинні знати, що відповіді на помилки можуть містити і тіло повідомлення. Ось куди йде пояснювальна інформація про помилку, якщо ви її дуже хочете. Не ламайте семантику лише тому, що ви параноїчні щодо жирних пальців. На рівні HTTP, це не має значення , зіпсували ви вгору , як /itms/1234або /items/12234.
cHao

27

HTTP 404 це правильно, оскільки сервер розуміє, який ресурс просить клієнт, але у нього немає цього ресурсу.

Те, що ви працюєте з "REST API", є ключовим. API повинен вести себе так, ніби він виконує репрезентативну передачу стану, а не виконує функцію. (Звичайно, термін "REST" набув більш широкого значення, але ви все одно можете використовувати його буквальне значення для хорошого ефекту тут.) Клієнт запитав про стан ресурсу, описаний URL http://example.com/restapi/device/123/info. Рядок запитів ( /deviceinfo?id=123) не змінить ситуацію. Сервер знає, що ви просите передати стан пристрою 123, але він не визнає це відомим ресурсом. Звідси HTTP 404.

Інші можливі відповіді, обговорені тут, також мають конкретне значення:

  • HTTP 200- Ми отримали для вас державу; це в органі відповіді.
  • HTTP 204- Ми отримали для вас державу; це порожнє.
  • HTTP 400- Ми не можемо сказати, про який ресурс ви просите. Виправте свою URL-адресу.
  • HTTP 500- Ми вийшли з ладу. Не ваша вина.

Див. RFC 2616 сек. 10 відповідно.


Я згоден з вашим питанням щодо цього. Якщо сервер повертав 404, це матиме більше сенсу, ніж те, що він робить (500). Дякую.
JYelton

11

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

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


Я б ставлюся до обох ваших прикладів ( http://example.com/restapi/deviceinfo?id=123і http://example.com/restapi/device/123/info) однаково - параметр 123є. Обидва випадки є різними способами структурування запиту для отримання інформації про пристрій для пристрою з ідентифікатором 123.

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

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

Якби всі параметри були дійсними, я б почав обробляти запит. Якщо система або будь-яка залежність (база даних, стороння служба, інша внутрішня служба) недоступна, я поверну 5xx код - 503 буде конкретним, але 500 також буде прийнятним. У будь-якому випадку я б повернув тіло з додатковими деталями. Вважайте, що якщо зовнішня залежність повідомляє про час очікування 408 запиту, я б з’їв це і повернув 500 моєму клієнту, що дозволить клієнту отримати 408, лише якщо час запиту до моєї системи закінчився. Якщо система зможе виконати запит, я поверну 200 та відповідний орган.

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

Єдиний час повернення 404 - це якщо сервер не мав /deviceinfoкінцевої або /device/:id/infoкінцевої точки.

Я б не вважав ідентифікатор, який не є таким, як ресурс, який не знайдено. Ресурс - це інформація про пристрій для певного пристрою (у вашому прикладі). Повернення 404 означало б, що ресурс (інформація про пристрій) не існує. 200 з відповідним корпусом означає, що система дійсно може надавати інформацію про пристрій. Може бути або не бути пристроєм із зазначеним ідентифікатором.


1
@RobertHarvey Так. Помилок не було. Тільки тому, що сервер створив GUID і надіслав його клієнту, не означає, що інша операція його видалила. Запит / відповідь був успішним. Команда або запит, представлені запитом, не повертають дані. Для мене це не провал. Це може бути винятком, але я не переконаний, що гідний 5 хв.
Томас Оуенс

2
Якби я розробляв цей API, який я запитую, я б його повернув 200 з тілом, яке потім містить щось для ефекту device: 123; status: not found;. Тоді я знаю, що запит спрацював, і що API повідомляє мені корисну інформацію.
JYelton

7
@Blrfl Це підкріплено (хоча і не "доведено") формулюванням багатьох веб-сайтів на 500 сторінках, як правило, щось на кшталт "Ми помилилися і будемо розслідувати". На мій погляд, належним чином функціонує сервер ніколи не надсилає 500, за винятком, можливо, у випадку космічних променів.
mbrig

6
Http не має поняття "кінцевої точки", не має відповідного розрізнення між змінною та рештою URL-адреси, а отже, не дає спокою. У вас може бути одна система маршрутизації, яка відповідає регексу і спрямовує тисячі URL-адрес до однієї функції контролера, але це детальна інформація про реалізацію, а не фундаментальна частина API. Відповідь 200 на отримання є лише у випадку, коли запитується ресурс. У цьому випадку клієнт хоче представити ресурс, який не існує, тому 404 є правильною відповіддю.
bdsl

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

5

Помилка HTTP серії 500 свідчить про несправність сервера. Крім 501 Not Implementedі 505 HTTP Version Not Supported, використовуючи ці коди помилок несе значення , що повторювати запит на більш пізній час може домогтися успіху (хоча тільки 503 Service Unavailableявно говорить про це). В ідеалі сервер ніколи не повинен виробляти один з цих кодів, хоча неможливість написання програмного забезпечення без помилок і забезпечення сервера нескінченними ресурсами означає, що вони вам будуть потрібні час від часу.

Для результату "об'єкта не існує", ви, ймовірно, повинні повернутися або 404 Not Found(коли запит призначений для об'єкта по імені), або 200 Successз порожнім тілом результату (під час пошуку об'єкта за атрибутами). 204 No Contentвиглядає заманливо, але я б використовував його лише в тих випадках, коли очікуваний результат - відсутність органу реагування.


1

Як клієнт вашого API, коли я здійснюю будь-який із цих дзвінків:

  1. http://example.com/restapi/deviceinfo?id=123
  2. http://example.com/restapi/device/123/info

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

Щодо API REST, я вважаю, що 400 та 500 кодів статусу є чимось на зразок винятку. Ви використовуєте їх для вказівки, коли ви не можете повернути "нормальну" відповідь на отриманий запит, тому клієнту потрібно буде зробити щось виняткове, а не обробляти інформацію, яку він очікував отримати.

Це означає, що як споживач API, я можу використовувати якусь функцію перевіреного спокою-виклику, яка отримує відповідь або кидає виняток. Це чудово; моя нормальна логіка може бути прямим кодом, і я можу організувати обробку помилок так само, як і в локальному коді. Неочікувані 404 будуть проявлятися як винятки "не знайдено ресурсів" без того, щоб я взагалі нічого не робив, не як помилки "відсутніх атрибутів", коли я згодом обробляю { errorMessage: "Device 123 not found" }так, ніби це був DeviceInfoоб'єкт.

Якщо причина того, що кінцева точка http://example.com/restapi/deviceinfo буде знайдена, а це тільки id=123що це не так , і так повернутися 200 з повідомленням про помилку в тілі, то ви створюєте точно такий же вигляд проблем інтерфейсу як функції C , які можуть повертати або правильний результат або код помилки або методи, які вказують на проблеми шляхом довільного поверненняnull. Користувачеві вашого інтерфейсу набагато приємніше помилки, зазначені через "окремий" канал від регулярних повернень. Це стосується і тут, навіть якщо відповіді HTTP 200, 404 та 500 - це той самий канал з точки зору низького рівня. Вони стандартизовані і легко розрізняються, тому моя клієнтська програма REST може легко перемикати такі статуси, щоб перетворити їх на належні структури моєї мови; щоб зробити те ж саме з шаром JSON (де ви завжди говорите 200 і даєте мені або DeviceInfoповідомлення про помилку), мені потрібно вкласти деякі знання про схеми JSON, які ви використовуєте.

Тож використовуйте 200 лише тоді, коли ви можете повернути дійсне значення очікуваного типу (саме тому ви http://example.com/restapi/search-devices?colour=blueможете повернути 200 із порожнім масивом, якщо немає синіх пристроїв; порожній масив - це дійсний масив та розумну відповідь на запит "I хотіли б деталі всіх синіх пристроїв "). Якщо ви не можете, скористайтеся найбільш підходящим кодом статусу не 200. Навіть незважаючи на те, що "пристрій 123 не існує" є правильною відповіддю на "дайте мені деталі пристрою 123", і це не помилка для сервера , це виняток для очікування клієнта, що вони отримають назад DeviceInfoі повинні не повідомляється як про звичайну відповідь "ось те, про що ви просили".


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

0

Ви можете використовувати помилку 422 Unprocessable Entity для відмежування від 404 не знайдено . 422 означає, що сервер розуміє запит, але він не може дати належну відповідь. Я використовую цей код у подібних ситуаціях.


4
У цій статті більш докладно описано використання 422. Я не думаю, що цей код помилки тут дійсно застосовний.
Роберт Харві

Дякую, дуже корисно! Мені доведеться поглибити цю тему!
FiNeX

0

Помилка 500 зазвичай вказує на те, що запит вийшов з ладу на стороні сервера; у підприємницькому середовищі ці помилки трактуються як яйце в обличчя і їх уникають.

Помилка 4xx повинна сигналізувати програмісту, що кінцева точка (ресурс) API не існує. Отже, як тільки буде досягнуто відповідної кінцевої точки, будь-яке поводження з помилками з цього моменту є відповідальністю програміста API, з яким слід поводитися граціозно, тобто з повідомленням про помилку у відповіді 200.


1
Отже, ви говорите "не використовуйте 500, тому що ви не зламаєте сервер?"
Роберт Харві

0

Хоча w3 зазначає, що 404 використовується, коли жодна інша відповідь не застосовується , хіба це не те, для чого відповідь 204 (Без вмісту)? Запит був дійсним з точки зору обробки, і сервер обробив запит і отримав результат. Це успіх, який схиляється до 2xx відповідей. Не було вмісту для цього конкретного запиту, тому 204 повідомляє користувачеві, що в їх запиті нічого поганого, але нічого там немає.

Ви також можете зробити слабкий випадок, що 409 (конфлікт) є відповідною відповіддю. Хоча 409 найчастіше використовується для POST, це говорить

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

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


3
Ні, відповідь 204 на запит на отримання має сенс лише тоді, коли запитуваний ресурс знайдений, а його представлення має рівно нуль символів.
bdsl

0

Інші відповіді висвітлюють це, але я просто хотів зазначити, що помилка серії 500 означає «я зіпсував». У цьому випадку "Я" означає API, тому некерована помилка сервера чи подібне. Помилка серії 400 означає "ви заплуталися" - абонент API надіслав щось неправильне.


-4

Інші користувачі дали вагомі відповіді, що робити, якщо ви хочете пройти книгу.

Однак я б запропонував, що ви занадто багато читаєте в СВІТЛО і абсолютно кошерні по відношенню до цього.

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

Існує інший підхід: повністю уникайте RESTfulness і використовуйте його просто як протокол зв'язку та нічого іншого. Це означає, що єдині відповіді, які потрібно повернути, - це "HTTP 200 ОК" та "Помилка внутрішнього сервера HTTP 500", оскільки що стосується протоколу зв'язку, то будь-яка спроба спілкування може мати лише два результати: або запит був успішно виконаний доставляється на сервер, чи ні.

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

Отже, підсумок - я б рекомендував повернути "HTTP 200 ОК", а в корисному навантаженні відповіді ("тіло вмісту відповіді" в мові HTTP) мати специфічний для програми код коду помилки, який говорить "Ідентифікатор не знайдений" або інше.


Судячи з голосів, я думаю, що я мав пошкодити почуття деяких людей. А може, якась інша частина їхнього тіла. C -: =
Майк Накіс

Вони справді повинні прочитати це: blogs.dropbox.com/developers/2015/04/…
Майк Накіс

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

@cHao так, я вважаю, що частина, яка говорить "Dropbox в даний час використовує близько 10 різних кодів статусу (8 помилок і 2 для успіху), але ми плануємо зменшити це число в майбутній версії API" нічого не означала ти.
Майк Накіс

Це не означало, що ви отримуєте від цього. Якщо вони знають, що роблять, то, в самому крайньому випадку, вони звели б це до одного успіху та чотирьох кодів помилок (400, 401, 404 та 500), оскільки вони, очевидно, дбають про умовності.
cHao
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.