Должен ли я возвращать статус HTTP 400 (неверный запрос), если параметр синтаксически правильный, но нарушает бизнес-правило?

56

Скажем, у меня есть конечная точка REST, которая принимает целое число в качестве параметра:

/makeWaffles?numberOfWaffles=3

В этом случае я хочу, чтобы число было положительным, потому что я не могу сделать отрицательное число вафель (а запрос 0 вафель - пустая трата времени). Поэтому я хочу отклонить любой запрос, который не содержит положительного целого числа. Я также хочу отклонить запрос, который превышает некоторое максимальное целое число (скажем, пока это MAX_INTEGER).

Если кто-то запрашивает не положительное число вафель, должен ли я вернуть статус HTTP 400 (Bad Request)? Сначала я подумал: да, это неправильный номер для выполнения запроса. Тем не менее, RFC не упоминает бизнес-правила в качестве причины, чтобы бросить его:

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

Бизнес-правило не подпадает ни под один из этих трех примеров. Это синтаксически правильно, правильно оформлено, и это не обманчивая маршрутизация запросов.

Так должен ли я возвращать статус HTTP 400 (неверный запрос), если параметр синтаксически правильный, но нарушает бизнес-правило? Или есть более подходящий статус для возвращения?

Thunderforge
источник

Ответы:

38

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

RFC 2616 (июнь 1999 г.)

10.4.1 400 неправильных запросов

Сервер не может понять запрос из-за неправильного синтаксиса. Клиент НЕ ДОЛЖЕН повторять запрос без изменений.

Что касается данного RFC, этот код состояния применяется только к синтаксически неверным запросам. Был пробел в кодах статуса для семантической проверки. Таким образом, когда появился RFC 4918, появился новый код.

RFC 4918 (июнь 2007 г.)

11.2. 422 необработанного объекта

Код состояния 422 (Unprocessable Entity) означает, что сервер понимает тип содержимого объекта запроса (следовательно, код состояния 415 (Unsupported Media Type) является неподходящим), и синтаксис объекта запроса является правильным (таким образом, 400 (неверный запрос) ) код состояния не подходит), но не удалось обработать содержащиеся в нем инструкции. Например, это условие ошибки может возникать, если тело запроса XML содержит правильно сформированные (то есть синтаксически правильные), но семантически ошибочные инструкции XML.

422 Unprocessable Entity был создан, чтобы заполнить пробел семантической проверки в исходной спецификации кодов состояния 4xx. Тем не менее, в 2014 году появился еще один соответствующий RFC, который обобщил 400, чтобы больше не относиться к синтаксису .

RFC 7231 (июнь 2014 г., явно устарел RFC 2616)

6.5.1. ошибка 400, неверный запрос

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

Обратите внимание, что в описании 422 говорится, что причина 400 неуместна в том, что 400 (начиная с RFC 2616) следует возвращать только для синтаксиса неверного запроса. Однако, начиная с RFC 7231, строгое определение синтаксической ошибки больше не относится к 400 .

Возвращаясь к рассматриваемому вопросу: хотя с технической точки зрения 422 технически более специфичен, с учетом этого контекста я мог видеть, что 400 или 422 используются для семантической проверки параметров API. Я не решаюсь использовать 422 в своих собственных API, потому что определение 422 технически устарело на данный момент (хотя я не знаю, признано ли оно где-либо официально). Статья, на которую ссылается в ответе Фрэн, которая поощряет использование 422, была написана в 2012 году, за два года до того, как RFC 7231 разъяснил HTTP 400. Просто убедитесь, что стандартизировали один или другой.

Кайл Маквей
источник
42

Я прочитал первый ответ и на самом деле не согласился с ним, потому что, по крайней мере в моем чтении, неверный запрос (400) означает: «Я даже не могу обработать ваш запрос, потому что что-то в корне неправильно». И я нашел этот пост, который оправдывает возвращение 422.

от IETF

422 Unprocessable Entity (WebDAV; RFC 4918) Запрос был правильно сформирован, но не мог быть выполнен из-за семантических ошибок

Это кажется более подходящим ответом, поскольку ваш запрос правильно сформирован, но не соответствует правилам проверки.

Fran
источник
5
Я слышал, что это описывается как «400 означает плохой синтаксис, 422 означает плохую семантику».
cbojar
33
Все коды x00 являются универсальными кодами "catch all". А 400 не является неуместным , просто менее конкретным .
Джек,
1
Хороший ответ, но ответ @GoFree имеет для меня больше смысла.
Эвертон
2
Есть действительно веские аргументы в пользу возврата кодов, которые все знают. Абсолютно все должны будут искать 422, и я держу пари, что большинство все еще не будет знать, что с этим делать.
Сильванаар
9

Нет, не стоит. HTTP-коды предназначены для уровня HTTP вашего приложения. Бизнес-правила - это совершенно другой уровень и зависят от приложения, поэтому вам нужно придумать свой собственный «протокол».

Представьте, что произошел апокалипсис, и вы должны переключиться с протокола HTTP на использование голубей. У голубей нет никаких кодов возврата, поэтому вам нужно будет изменить свой бизнес-уровень, чтобы приспособиться к этому. Но ваш бизнес на самом деле не изменился, поэтому вам не нужно менять бизнес-уровень. Это показывает тесную связь между этими двумя уровнями (транспорт и бизнес).

Вернемся к вопросу: что вы должны сделать, это вернуть «200 OK» с телом, описывающим, что произошло с запросом. В спецификации четко сказано так:

https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1 .

200 ОК

Запрос успешно выполнен. Информация , возвращаемая с ответом зависит от метода , используемого в запросе , например ,

POST объект, описывающий или содержащий результат действия;

Успешен ли ваш HTTP-запрос? Да, веб-сервер знает, что делать с этим запросом (например, передать его серверной части вашего приложения). Затем веб-сервер передает этот запрос серверной части вашего приложения, которая принимает POST-данные, обрабатывает их (проверяет их в вашем случае) и возвращает нормальный ответ (в теле HTTP-ответа) клиентской части вашего приложения. , Этот ответ от серверной части приложения может быть либо «Отлично, отправленные вами данные верны», либо «Извините, отправленные вами данные недействительны». И ваша клиентская часть приложения должна понять, что означает ответ.

PS: «400 Bad Request» означает, что веб-сервер не понял, что вы хотите от него. Это означает, что ваша серверная часть вашего приложения даже не получила запрос. Или, по крайней мере, это означает, что это означает :-)

РЕДАКТИРОВАТЬ : Я только что понял, что вы делаете запрос GET, а не POST. Это плохая идея, потому что GET не должен изменять состояние приложения. GET должен просто получать данные с сервера. Но в своем запросе вы фактически меняете состояние приложения, поэтому вам действительно следует использовать POST.

GoFree
источник
1
Да, возвращение 404 в этом случае нормально. Я не говорю, что сервер всегда должен отправлять 200 ОК с объяснением в теле.
GoFree
Лучшее объяснение я видел до сих пор. У меня тот же вопрос, и кажется, что все слово думает иначе, чем я и ты @GoFree
Эвертон
@ GoFree Это действительно хороший ответ, чтобы переосмыслить дизайн API. Но разве не так, что мы используем HTTP и его код ответа в качестве важной части уровня бизнес-правил, когда мы используем REST API?
Томас Лаурия
1
@Thomas Lauria Я еще не видел надлежащей реализации RESTFUL API. Однако REST API сегодня является модным словом, поэтому каждая компания должна использовать его (слово, а не технологию), фактически не понимая концепцию, стоящую за ним. Так что да, это используется неправильно везде. Программисты обычно создают не REST API, а HTTP API или API OVER HTTP. На самом деле одной из немногих хороших реализаций RESTFUL является сам HTTP :)
GoFree
1
Использование 200-ОК особенно логично, если приложение включает в себя поле «ошибка» в теле ответа для описания любых ошибок бизнес-уровня, таких как слишком высокое или слишком низкое или отсутствующее входное значение, товара нет на складе и т. Д.
Роланд
8

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

Исключением является случай, когда бизнес-правило связано с безопасностью (тогда 401 Unauthorizedили 403 Forbiddenбудет лучше). В качестве альтернативы, если отправка 400 будет утечка информации о существовании чего-то, и тогда 404 Not Foundможет быть более подходящим.

Telastyn
источник
-3

Не уверен, что все согласятся, но мы используем 409 - Конфликт. Многие утверждают, что 409 - это скорее конфликт с состоянием системы, но мы согласились с интерпретацией, что конфликт значений данных, выходящий за пределы допустимого диапазона, может быть исправлен запрашивающей стороной и допустимым использованием 409. 422 Я думаю, что это было бы разумно в качестве запроса правильно сформирован, но не может быть обработан в соответствии с запросом. Однако я полагаю, что если вы не хотите реализовывать множество ответов, просто дать 400 все равно приемлемо.

DLB
источник
5
409 означает «состояние, в которое вы пытаетесь поместить это, находится в конфликте с состоянием, в которое пытается вставить это другой клиент», это означает, что он блокирует одновременные записи (например, с использованием ETags)
Джек