Должно ли «Нет результатов» быть ошибкой в ​​ответе RESTful?

52

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

Кто-то использует это для поиска названного продукта pineapple-banana flavoured cookiesи, очевидно, не найдет никаких результатов.

Должно ли это быть возвращено как ошибка? Поиск не дал сбоя, API выполнил поиск и успешно завершил поиск файлов cookie. API не должен возвращаться 404, потому что API действительно был найден.

Берри М.
источник
6
Возможные дубликаты RESTful API представляют отсутствие вещи
gnat
3
@gnat: это не дубликат, потому что другой вопрос касается конкретного ресурса, а не запроса к нескольким ресурсам.
Грег Бургхардт
7
Аналогично, предположим, что у вас есть функция, которая возвращает массив объектов. Если нет объектов, соответствующих конкретному варианту использования, вы бы предпочли функцию через исключение или возвратили пустой массив?
Кевин - Восстановить Монику
2
@AakashM Возвращение HTTP-204 к GET-запросу довольно необычно, я знаю, что нигде такого не видел. Насколько я знаю, HTTP-204 обычно используется в качестве ответа при изменении ресурса на сервере, например, запросов POST / PUT / DELETE.
Раду Мурзеа

Ответы:

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, если вы возвращали null, сериализованный как пустую строку, которую я воссоздаю
Ewan
15
Этот. При создании RESTful API важно не API, а часть API. Хороший API облегчает жизнь клиентам / потребителям. Пустой массив легче обрабатывать, чем нулевые значения / исключения / коды состояния.
Гуран
37

Всякий раз, когда выбираете код HTTP, вы всегда должны задать этот вопрос:

Что может / будет / должен любой произвольный клиент сделать с ответом?

  1. Должен ли клиент всегда рассматривать ответ как неудачу? Затем вы хотите 4xx или 5xx, в зависимости от того, является ли проблема входом клиента или процессов сервера.
  2. Должен ли клиент сделать запрос в другом месте? Тогда 3xx для вас.
  3. Сделал ли сервер то, что просил клиент (успешно)? Это 2хх.

Всегда решайте, в каком диапазоне должен быть ваш код ответа. Это быстро устраняет множество кодов ответов в качестве опций и (что может быть более важно) упрощает следование семантике кодов. Посмотрите начальные разделы документации кода HTTP для объяснения того, что представляет каждая категория кодов.

В этом случае клиент запросил список результатов, получив фильтр от действующей, существующей конечной точки, и получил разрешение на доступ к нему. Сервер смог обработать запрос и определить соответствующие данные для возврата (без элементов), поэтому запрос был успешным. Просто так получилось, что фильтр, который они дали, отфильтровал все результаты. Сервер не может определить, хотел ли клиент этого или нет, поскольку для некоторых клиентов это может быть ожидаемым результатом. Если это так или иначе является проблемой для клиентского кода, клиент должен определить, проверить и обработать его соответствующим образом. Так что это явно 2xx.

Теперь вопрос: "Какие 2xx?" Это зависит от того, как вы намереваетесь ответить на запрос сервера.

  • Вы отправите обратно представление пустого списка, как описывают некоторые другие ответы ? Если это так, вы хотите 200. 200 означает, что на сервере не возникло проблем, и он имеет представление результатов для использования клиентом. Вероятно, это наиболее удобный способ ответа для ваших потребителей, которые могут просто проанализировать ответ независимо от того, были ли результаты или нет, а затем выяснить, как обрабатывать пустой список самостоятельно.
  • 204 не является семантически неправильным здесь, но вы должны будете ответить без какого-либо тела сообщения . Это означает, что весь код клиента должен был бы явно проверять различные HTTP-коды (или, по крайней мере, на отсутствие тела сообщения) и обрабатывать их отдельно. Это неудобно и, скорее всего, приведет к плохому поведению клиентов.

Другие не применимы вообще:

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

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

jpmc26
источник
5
Был бы заинтересован мнение downvoter. Я не думаю , что это даже спорно.
jpmc26
2
Я не думаю, что клиенты должны проверять 204 явно. Все, что им нужно, - это способность обрабатывать нулевой объект ответа. Работа фреймворка HTTP - обрабатывать 204, пропуская часть "parse the body". 200 с Content-Lenght 4 и body null - это то же самое.
Agent_L
1
@Agent_L Вы правы, что если сервер отвечает структурой, несовместимой с обычным ответом (например, помещая nullтуда, где обычно есть список), вы не сможете воспользоваться преимуществами согласованности даже с 200. Однако, что я описываю, это использование ответ, который согласуется с нормальной структурой и имеет пустой список, куда обычно попадает список результатов. 204 отнимает любую возможность иметь такой последовательный ответ. Кроме того, даже в клиентских библиотеках HTTP, в которых есть вспомогательные функции, вам часто (как правило?) Приходится делать явный вызов для разбора JSON.
jpmc26
@Agent_L В частности, со списками, вызывающие абоненты часто могут просто позволить своему коду нормально работать над пустым списком (например, зацикливаясь на нем), в то время как им потребуется явная проверка какого-либо вида для обработки другого типа представления.
jpmc26
16

Нет. Использование 404 для обозначения «ваш запрос был обработан, но совпадений не было» ужасно, потому что:

  • условный поток, основанный на обработке исключений (т. е. принуждение неисключительного результата к созданию и обработке исключения в клиенте, которое может быть неэффективным и неудобным)

  • неоднозначность между «реальной» страницей не найдена, вы ввели конечную точку неверные ошибки

Важно помнить, что всегда есть клиент для десериализации сообщения и того, что возвращает этот клиент, это важно; не сериализация.

Если клиент должен вернуть ноль, используйте сериализацию ноль. Если клиент должен вернуть пустой массив, используйте [], если клиент должен сгенерировать ошибку, используйте 500 и передайте сообщение об ошибке

Ewan
источник
2
Почему сервер должен заботиться о том, что клиент делает с информацией? (PS: я не тот, кто отклонил ваш ответ).
Раду Мурзеа
в этом контексте «клиент» - это код, работающий на клиентском устройстве, который предоставляет сервис клиентскому приложению. Он должен иметь возможность выставлять методы служб и возвращать результаты в соответствии с намерениями службы. Вам нужна пара клиент-сервер, чтобы коммуникация функционировала вообще
Ewan
3
Конечно, не используйте 5xx для ошибок клиента . Предпочитаю 4xx в этом случае.
Кевин
1
Хотя разве это не должен быть «сервер», а не «клиент» в большинстве этих случаев? Это сервер, который обрабатывает запрос и обслуживает ответ, а клиент просто обрабатывает ответ? В этом случае код 5xx будет в порядке, так как это ошибка сервера, а не ошибка клиента?
MrWhite,
2
Проблема всех кодов ошибок в том, что они имеют значение в http. 500 - единственный код, который подходит для случаев, когда ваша служба выдает исключение
Ewan
9

Помимо очень хорошего ответа @ Ewan:

Если запрос является видом, который возвращает набор результатов, то пустой набор логически так же уместен, как набор из одного или набор из нескольких. Вообще говоря, по причинам, которые утверждает @Ewan, преобразование пустого набора в ошибку приносит больше пользы, чем пользы, и это просто не нужно.

Если запрос является видом, который ищет и возвращает конкретный синглтон (который, как ожидается, будет найден, например, точное совпадение по идентификатору), тогда не найден логически подходящий возможный ответ.

Эрик Эйдт
источник
Да, я точно так и думал на ответе Эвана.
Вальфрат
5

Вы предполагаете, что код должен предпринять специальное действие, когда данные не возвращаются, но это может быть не так. Код может просто искать количество продуктов, или добавлять результаты в список или любое количество вещей. Вы должны давать пользователю «ошибку», только если на самом деле есть ошибка.

Джон Смит
источник
3
«Вы должны давать пользователю« ошибку », только если на самом деле есть ошибка». - это. Пустой набор результатов при выполнении «поиска» обычно не является «ошибкой». Однако, если не удалось установить соединение с базой данных, что означало, что поиск фактически не мог быть выполнен, тогда пустой набор результатов (и без ошибок) в противном случае был бы неоднозначным. В этом случае было бы уместно какое-то состояние ошибки (возможно, вместе с пустым набором результатов - в зависимости от того, как определен API).
MrWhite,
0

Когда я использую API, в качестве клиента мне приходится обрабатывать случаи «успеха», отличные от случаев «ошибок»; У меня нет выбора там. Следовательно, вы должны возвращать ошибку в ситуациях, которые клиент хочет обрабатывать по-разному, и успех в ситуациях, которые клиент хочет обрабатывать одинаково.

Если я сделаю запрос, который теоретически мог бы вернуть любое количество результатов, ноль, один, двести и т. Д., Тогда вы должны возвращать «успех» всякий раз, когда API предоставляет полный список всех результатов. И, возможно, в случаях, когда имеется много результатов, вы вернули частичный список результатов, чтобы избежать чрезмерного размера, и существует согласованный способ получения других результатов. Это потому, что, как клиент, я часто хочу обрабатывать случай нулевых результатов, как случай большего количества результатов. Я мог бы относиться к этому по-другому, но я не хочу быть вынужденным.

Это отличается в том случае, если я ищу значение. Я ожидаю ровно одного результата, ценности, которую я ищу. И мне нужен этот один результат, чтобы продолжить то, что я хочу сделать осмысленным образом. Здесь гораздо более приемлемо возвращать статус 404 для случая, когда значение отсутствует, так как в любом случае мне нужно обрабатывать этот случай иначе.

Сводка: если клиент ожидает какого-либо числа результатов, от нуля до большого числа, то возвращает «успех», если все результаты получены, даже если число равно нулю. Если клиент ожидает ровно один результат, верните успех, если результат найден, и ошибку, если результат не найден.

gnasher729
источник