Czy powinienem zwrócić status HTTP 400 (Błędne żądanie), jeśli parametr jest poprawny pod względem składniowym, ale narusza regułę biznesową?

56

Powiedz, że mam punkt końcowy REST, który przyjmuje liczbę całkowitą jako parametr:

/makeWaffles?numberOfWaffles=3

W tym przypadku chcę, aby liczba była dodatnia, ponieważ nie mogę zrobić ujemnej liczby gofrów (a żądanie 0 gofrów to strata czasu). Chcę więc odrzucić każde żądanie, które nie zawiera dodatniej liczby całkowitej. Chcę również odrzucić żądanie, które przekracza pewną maksymalną liczbę całkowitą (powiedzmy na razie, że jest to MAX_INTEGER).

W przypadku, gdy ktoś zażąda nie dodatniej liczby gofrów, czy powinienem zwrócić status HTTP 400 (Błędne żądanie)? Moje pierwsze zdanie brzmi „tak”: nie jest to dla mnie prawidłowy numer, aby zrealizować prośbę. Jednak RFC nie wymienia reguł biznesowych jako powodu do jego rzucenia:

Kod statusu 400 (Błędne żądanie) wskazuje, że serwer nie może lub nie przetworzy żądania z powodu czegoś, co jest postrzegane jako błąd klienta (np. Źle sformułowana składnia żądania, nieprawidłowe sformułowanie komunikatu żądania lub oszukańczy routing żądania).

Reguła biznesowa nie mieści się w żadnym z tych trzech przykładów. Jest poprawny pod względem składniowym, ma odpowiednie ramy i nie jest zwodniczym routingiem żądań.

Czy powinienem więc zwrócić status HTTP 400 (Błędne żądanie), jeśli parametr jest poprawny pod względem składniowym, ale narusza regułę biznesową? Czy jest bardziej odpowiedni status do zwrócenia?

Thunderforge
źródło

Odpowiedzi:

38

To wielkie pytanie i wciąż bardzo aktualne, biorąc pod uwagę kontekst historyczny (i pozornie sprzeczne definicje) kodów powrotu HTTP. Nawet wśród odpowiedzi na to pytanie istnieją sprzeczne definicje. Można to wyjaśnić, poruszając się chronologicznie.

RFC 2616 (czerwiec 1999)

10.4.1 400 Zła prośba

Serwer nie mógł zrozumieć żądania z powodu nieprawidłowej składni. Klient NIE POWINIEN powtarzać żądania bez modyfikacji.

Począwszy od tego dokumentu RFC, ten kod statusu został zastosowany wyłącznie do nieprawidłowo składniowych żądań. Wystąpiła luka w kodach statusu dla weryfikacji semantycznej. Tak więc, kiedy pojawiła się RFC 4918, narodził się nowy kod.

RFC 4918 (czerwiec 2007)

11.2 422 Podmiot nieprzetworzony

Kod statusu 422 (Unprocessable Entity) oznacza, że ​​serwer rozumie typ treści encji żądania (stąd kod statusu 415 (Unsupported Media Type) jest nieodpowiedni), a składnia encji żądania jest poprawna (a zatem 400 (Bad Request ) kod stanu jest nieodpowiedni), ale nie mógł przetworzyć zawartych instrukcji. Na przykład ten warunek błędu może wystąpić, jeśli treść żądania XML zawiera dobrze sformułowane (tj. Poprawne składniowo), ale semantycznie błędne instrukcje XML.

422 Jednostka nieprzetworzona została utworzona w celu wypełnienia luki w sprawdzaniu poprawności semantycznej w oryginalnej specyfikacji kodów statusu 4xx. Jednak w 2014 r. Pojawiła się kolejna istotna specyfikacja RFC, która uogólniła 400, aby nie była już specyficzna dla składni .

RFC 7231 (czerwiec 2014, wyraźnie przestarzałe RFC 2616)

6.5.1 400 złych wniosków

Kod statusu 400 (Błędne żądanie) wskazuje, że serwer nie może lub nie przetworzy żądania z powodu czegoś, co jest postrzegane jako błąd klienta (np. Źle sformułowana składnia żądania, nieprawidłowe sformułowanie komunikatu żądania lub oszukańczy routing żądania).

Zauważ, że opis 422 mówi, że przyczyną 400 jest nieodpowiednia przyczyna, ponieważ 400 (od RFC 2616) powinno być zwracane tylko dla składni złych żądań. Jednak od RFC 7231 ścisła definicja błędu składniowego nie ma już zastosowania do 400 .

Wracając do pytania: chociaż 422 jest technicznie bardziej szczegółowe, biorąc pod uwagę ten kontekst, mogłem zobaczyć, że 400 lub 422 są używane do semantycznej weryfikacji parametrów API. Waham się przed użyciem 422 we własnych interfejsach API, ponieważ definicja 422 jest w tym momencie technicznie nieaktualna (chociaż nie wiem, czy jest to oficjalnie rozpoznane). Artykuł przywołany w odpowiedzi Frana, który zachęca do korzystania z 422, został napisany w 2012 r., Dwa lata przed tym, jak RFC 7231 wyjaśnił HTTP 400. Pamiętaj o standaryzacji jednego lub drugiego.

Kyle McVay
źródło
42

Przeczytałem pierwszą odpowiedź i tak naprawdę się z nią nie zgadzałem, ponieważ, przynajmniej w moim czytaniu, zła prośba (400) oznacza: „Nie mogę nawet obsłużyć twojej prośby, ponieważ coś jest zasadniczo nie tak”. I znalazłem ten post, który uzasadnia zwrot 422.

z IETF

422 Nieprzetworzona jednostka (WebDAV; RFC 4918) Żądanie zostało poprawnie sformułowane, ale nie można było go zrealizować z powodu błędów semantycznych

To wydaje się być bardziej odpowiednią odpowiedzią, ponieważ twoje zapytanie jest poprawnie sformułowane, ale nie spełnia twoich reguł sprawdzania poprawności.

Fran
źródło
5
Słyszałem, że opisano to jako „400 oznacza złą składnię, 422 oznacza złą semantykę”.
cbojar
33
Wszystkie kody x00 są kodami rodzajowymi „catch all”. 400 nie jest niewłaściwe , tylko mniej szczegółowe .
Jack
1
Dobra odpowiedź, ale ansewer podane przez @GoFree większy sens dla mnie.
Ewerton
2
Istnieje naprawdę silny argument za zwracaniem kodów, który wszyscy znają. Absolutnie wszyscy będą musieli sprawdzić 422 i założę się, że większość nadal nie będzie wiedziała, co z tym zrobić.
sylvanaar
8

Tak, dane wejściowe, które nie są zgodne z dorozumianą umową punktu końcowego, to „coś, co jest postrzegane jako błąd klienta” i powinno zwrócić wartość 400.

Wyjątkiem jest sytuacja, w której reguła biznesowa jest związana z bezpieczeństwem (wtedy 401 Unauthorizedlub 403 Forbiddenbyłoby lepiej). Alternatywnie, jeśli wysłanie 400 spowoduje wyciek informacji o istnieniu czegoś, a wtedy 404 Not Foundmoże być bardziej odpowiednie.

Telastyn
źródło
8

Nie, nie powinieneś. Kody HTTP są przeznaczone dla warstwy HTTP Twojej aplikacji. Reguły biznesowe mają zupełnie inną warstwę i są specyficzne dla aplikacji, dlatego musisz wymyślić własny „protokół”.

Wyobraź sobie, że dzieje się apokalipsa i musisz przełączyć się z protokołu HTTP na używanie gołębi. Gołębie nie mają żadnych kodów powrotu, więc trzeba by zmienić warstwę biznesową, aby się do tego dostosować. Ale twoja firma tak naprawdę się nie zmieniła, więc nie musisz zmieniać warstwy biznesowej. Pokazuje ścisłe połączenie tych dwóch warstw (transport i biznes).

Wróć do pytania: Powinieneś zwrócić „200 OK” z treścią opisującą, co się stało z żądaniem. Specyfikacja wyraźnie mówi:

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

200 OK

Żądanie się powiodło. Zwracana z reakcji jest zależny od zastosowanej metody w zgłoszeniu , przykładowo

POST podmiot opisujący lub zawierający wynik działania;

Czy żądanie HTTP się powiodło? Tak, serwer WWW wie, co zrobić z tym żądaniem (np. Przekazać je do części aplikacji serwera). Następnie serwer WWW przekazuje to żądanie do części serwerowej aplikacji, która pobiera dane POSTed, przetwarza je (weryfikuje je w twoim przypadku) i zwraca normalną odpowiedź (w treści odpowiedzi HTTP) do części klienta aplikacji . Ta odpowiedź z części serwerowej aplikacji może brzmieć „Świetnie, dane, które mi przesłałeś, są prawidłowe” lub „Przykro mi, dane, które przesłałeś, są nieprawidłowe”. Rozumienie, co oznacza odpowiedź, zależy od części aplikacji klienta.

PS: „400 Błędne żądanie” oznacza, że serwer internetowy nie zrozumiał, czego od niego oczekujesz. Oznacza to, że część aplikacji na serwerze nie otrzymała nawet żądania. A przynajmniej tak to powinno oznaczać :-)

EDYCJA : Właśnie zdałem sobie sprawę, że wykonujesz żądanie GET, a nie POST. To zły pomysł, ponieważ GET nie powinien zmieniać stanu aplikacji. GET ma po prostu pobierać dane z serwera. Ale w swojej prośbie zmieniasz stan aplikacji, więc naprawdę powinieneś używać POST.

Iść wolno
źródło
1
Tak, w takim przypadku zwrot 404 jest w porządku. Nie twierdzę, że serwer powinien zawsze wysyłać 200 OK z wyjaśnieniem w treści.
GoFree,
Lepsze wyjaśnienie, jakie do tej pory widziałem. Mam to samo pytanie i wydaje się, że wszystkie słowa myśli differente ode mnie i @GoFree
Ewerton
@GoFree To naprawdę dobra odpowiedź na przemyślenie projektu API. Ale czy nie jest tak, że gdy używamy interfejsu API REST, używamy HTTP i jego kodu odpowiedzi jako znaczącej części warstwy reguł biznesowych?
Thomas Lauria
1
@Thomas Lauria Nie widziałem jeszcze poprawnej implementacji RESTFUL API. Jednak REST API jest dziś modnym słowem, więc każda firma musi go używać (słowo, nie technologia), nie rozumiejąc przy tym jego koncepcji. Tak, tak, wszędzie jest używany w niewłaściwy sposób. To, co zwykle tworzą programiści, to nie interfejs API REST, ale interfejs API HTTP lub API OVER HTTP. Właściwie jedną z niewielu dobrych implementacji RESTFUL jest sam HTTP :)
GoFree
1
Używanie 200-OK jest szczególnie logiczne, jeśli aplikacja zawiera pole „błąd” w treści odpowiedzi, aby opisać wszelkie błędy na poziomie biznesowym, takie jak zbyt wysoka lub zbyt niska lub brakująca wartość wejściowa, produkt niedostępny, itp.
Roland
-3

Nie jestem pewien, czy wszystko się zgodzi, ale używamy 409 - Konflikt. Wiele osób twierdzi, że 409 jest bardziej konfliktem ze stanem systemu, ale przyjęliśmy interpretację, że konflikt wartości danych poza akceptowanym zakresem może zostać naprawiony przez żądającego i dopuszczalne użycie 409. 422 Myślę, że uzasadnione byłoby żądanie jest poprawnie utworzony, ale nie może być przetwarzany zgodnie z żądaniem. Wybieram jednak, jeśli nie chcesz wdrożyć mnóstwa odpowiedzi, samo podanie 400 jest nadal dopuszczalne.

dlb
źródło
5
409 oznacza, że ​​„stan, w którym próbujesz to wprowadzić, jest w konflikcie ze stanem, w którym inny klient próbuje to wprowadzić”, służy do blokowania równoczesnych zapisów (na przykład przy użyciu znaczników ETag)
Jack