Pracuję nad projektem i po kłótni z ludźmi w pracy przez ponad godzinę. Postanowiłem wiedzieć, co mogą powiedzieć ludzie korzystający z wymiany stosów.
Piszemy API dla systemu, istnieje zapytanie, które powinno zwrócić drzewo Organizacji lub drzewo Celów.
Drzewo Organizacji to organizacja, w której użytkownik jest obecny. Innymi słowy, drzewo to powinno zawsze istnieć. W organizacji drzewo celów powinno być zawsze obecne. (od tego zaczął się argument). W przypadku, gdy drzewo nie istnieje, mój współpracownik zdecydował, że dobrze będzie odpowiedzieć na kod stanu 200. A potem zaczął prosić mnie o naprawienie mojego kodu, ponieważ aplikacja się rozpadała, gdy nie było drzewa.
Spróbuję oszczędzić płomieni i furii.
Zasugerowałem podniesienie błędu 404, gdy nie ma drzewa. To przynajmniej dałoby mi znać, że coś jest nie tak. Korzystając z 200, muszę dodać specjalne sprawdzenie do mojej odpowiedzi w wywołaniu zwrotnym powodzenia, aby obsłużyć błędy. Oczekuję, że otrzymam obiekt, ale mogę otrzymać pustą odpowiedź, ponieważ nic nie zostanie znalezione. Oznaczenie odpowiedzi jako 404 wydaje się całkowicie uczciwe. A potem wybuchła wojna i dostałem wiadomość, że nie rozumiem schematu kodu statusu HTTP. Więc jestem tutaj i pytam, co jest nie tak z 404 w tym przypadku? Dostałem nawet argument „Nic nie znalazłem , więc dobrze jest zwrócić 200”. Uważam, że to źle, ponieważ drzewo powinno być zawsze obecne. Jeśli nic nie znaleźliśmy i czegoś oczekujemy, powinno to być 404.
Więcej informacji,
Zapomniałem dodać pobrane adresy URL.
Organizacje
/OrgTree/Get
Cele
/GoalTree/GetByDate?versionDate=...
/GoalTree/GetById?versionId=...
Mój błąd, oba parametry są wymagane. Jeśli podana jest jakakolwiek wersjaData, którą można przeanalizować z datą, zwróci poprawkę zamknięcia. Jeśli wpiszesz coś w przeszłości, zwróci pierwszą wersję. Jeśli przez Id z identyfikatorem, który nie istnieje, podejrzewam, że zwróci pustą odpowiedź z 200.
Dodatkowy
Ponadto uważam, że najlepszą odpowiedzią na problem jest tworzenie domyślnych obiektów podczas tworzenia organizacji, brak drzewa nie powinien być prawidłowym przypadkiem i powinien być postrzegany jako zachowanie niezdefiniowane. Nie ma możliwości korzystania z konta bez obu drzew. Z tych powodów powinni być zawsze obecni.
też połączyłem to (jeden podobny, ale nie mogę go znaleźć)
http://viswaug.files.wordpress.com/2008/11/http-headers-status1.png
źródło
/GoalTree/GetById?versionId=CompletelyInvalidID
zwrócić? Niepowodzenie, ponieważ wymieniony zasób/GoalTree/GetById?versionId=CompletelyInvalidID
dosłownie nie został znaleziony.Odpowiedzi:
W razie wątpliwości zajrzyj do dokumentacji . Przejrzenie definicji W3C dla kodów statusu HTTP daje nam to:
W kontekście interfejsu API bardzo zależy to od sposobu tworzenia zapytań i pobierania obiektów. Ale moja interpretacja zawsze była taka:
200
kod powrotu , jeśli nie istnieje, zwróć poprawny404
kod.200
kodem. Uzasadnieniem tego jest to, że zapytanie było prawidłowe, powiodło się, a zapytanie nic nie zwróciło.Więc w tym przypadku masz rację , usługa nie szuka „konkretnej rzeczy”, żąda konkretnej rzeczy, jeśli czegoś nie znaleziono, powiedz to wyraźnie.
Myślę, że Wikipedia mówi najlepiej:
Wydaje mi się to całkiem jasne.
Odnośnie przykładowych żądań
W przypadku formatu zawsze zwracasz najbliższą wersję do tej daty. Nigdy nie zwróci obiektu, więc zawsze powinien powracać
200 OK
. Nawet jeśli byłby w stanie przyjąć zakres dat, a logika polegała na zwróceniu wszystkich obiektów w tym przedziale czasowym, zwracając 200 OK - 0 Wyniki są w porządku, ponieważ właśnie o to chodziło w żądaniu - zbiór rzeczy spełniających te kryteria.To ostatnie jest jednak inne, ponieważ pytasz o konkretny obiekt , prawdopodobnie unikalny, o tej tożsamości. Zwrócenie
200 OK
w tym przypadku jest nieprawidłowe, ponieważ żądany zasób nie istnieje i nie został znaleziony .Odnośnie wybierania kodów statusu
Wspomniałeś w komentarzu za pomocą kodu 5xx, ale twój system działa. Zostało zadane zapytanie, które nie działa i musi zostać przekazane do UA. Bez względu na to, jak je pokroisz, jest to terytorium 4xx.
Rozważ kosmitów pytających o nasz układ słoneczny
źródło
Ignorując fakt, że / GoalTree / Get * wygląda jak czasownik, a nie zasoby, zawsze powinieneś zwrócić 200, ponieważ URI / GoalTree / Get * reprezentują zasoby, które są zawsze dostępne dla dostępu i nie jest to błąd klienta, jeśli nie ma drzewa w wyniku prośba. Zwróć 200 z pustym zestawem, gdy nie ma elementu do zwrotu.
Używasz 404, jeśli zasób nie zostanie znaleziony, a nie, gdy nie ma encji.
Innymi słowy, jeśli chcesz zwrócić 404 za swoje obiekty, podaj im ich własne identyfikatory URI.
źródło
/GoalTree/GetById?versionId=12345
jest idealnie dobrym identyfikatorem URI (przynajmniej względnym), który identyfikuje określony zasób, a mianowicie dane odpowiadające identyfikatorowi wersji12345
w systemie. Jeśli nie ma danych o takim identyfikatorze, odpowiedź HTTP 404 jest całkowicie odpowiednia. Oczywiście treść odpowiedzi powinna w każdym przypadku zawierać odpowiednio sformatowaną odpowiedź (np. JSON, jeśli tego oczekują typowi klienci żądający takich zasobów), wskazując konkretny charakter i przyczynę błędu.To interesujące pytanie, ponieważ chodzi o specyfikację systemu.
Odpowiedź imel96 przekonała mnie, że 404 nie byłby właściwą odpowiedzią, ponieważ rodzina kodów 4xx dotyczy głównie błędów użytkownika / klienta , i to nie jest jeden. Adres URL jest poprawnie sformułowany i drzewo musi tam być; jeśli nie, system jest niespójny!
Dlatego jest to błąd serwera , tzn. Coś z rodziny 5xx. Prawdopodobnie ogólny błąd wewnętrzny serwera 500 lub usługa 503 niedostępna (usługa polega na „ściągnięciu drzewa, które musi tam być”).
źródło
Powiedziałbym, że może być poprawny kod odpowiedzi 200 lub 404 , w zależności od tego, jak spojrzysz na sytuację.
Chodzi o to, że kody odpowiedzi HTTP są zdefiniowane w kontekście serwera , który może dostarczać różne zasoby na podstawie ich adresów URL. W tym kontekście znaczenia
200 OK
i404 Not Found
są całkowicie jednoznaczne: pierwsza mówi „oto zasób, o który prosiłeś”, a druga mówi „przepraszam, nie mam takich zasobów”.Jednak w twojej sytuacji istnieje dodatkowa warstwa aplikacji między serwerem HTTP a rzeczywistymi żądanymi zasobami (drzewami). Aplikacja zajmuje rodzaj przestrzeni pośredniej, która nie jest dobrze zaadresowana w specyfikacji HTTP.
Z punktu widzenia serwera sieciowego, zastosowanie wygląda trochę jak zasób: to zazwyczaj plik na serwerze, zidentyfikowanego przez (część) adres URL, podobnie jak innych zasobów (np statycznych plików) serwer może służyć. Z drugiej strony jest to dziwny rodzaj zasobu, ponieważ składa się z kodu wykonywalnego, który dynamicznie określa treść, a nawet potencjalnie kod statusu odpowiedzi, dzięki czemu zachowuje się w pewien sposób bardziej jak mini-serwer.
W szczególności, w twoim przypadku serwer WWW może dobrze zlokalizować aplikację, ale aplikacja nie może zlokalizować żądanego podkatalogu (drzewa). Teraz, jeśli uważasz aplikację za rozszerzenie serwera , a podelement (drzewo) za rzeczywisty zasób, to odpowiednia jest odpowiedź 404 : serwer jedynie przekazał zadanie znalezienia rzeczywistego zasobu do aplikacji , które jej się nie udało.
Z drugiej strony, jeśli twoim zdaniem jest to, że aplikacja jest żądanym zasobem , serwer sieci powinien oczywiście zwrócić odpowiedź 200 ; w końcu aplikacja została znaleziona i wykonana poprawnie. Oczywiście w tym przypadku aplikacja powinna faktycznie zwrócić poprawną treść odpowiedzi w oczekiwanym formacie, wskazując (używając dowolnego protokołu wyższego poziomu, który koduje ten format), że nie znaleziono żadnych rzeczywistych danych pasujących do zapytania.
Oba te punkty widzenia mogą mieć sens. W większości przypadków , przynajmniej w przypadku aplikacji przeznaczonych do bezpośredniego dostępu przez HTTP za pomocą zwykłej przeglądarki internetowej, wolałbym poprzedni widok : użytkownik zasadniczo nie dba o szczegóły wewnętrzne, takie jak różnica między serwerem a aplikacją, po prostu dbać o to, czy dane, których chcieli, są, czy nie.
Jednak w konkretnym przypadku aplikacji zaprojektowanej do komunikowania się z innymi programami komputerowymi przy użyciu niestandardowego protokołu API wysokiego poziomu, wykorzystującego HTTP tylko jako warstwę transportową niskiego poziomu , należy argumentować na korzyść tego drugiego widoku : dla klienci współpracujący z taką aplikacją, wszystko, na czym naprawdę im zależy, na poziomie HTTP , to to, czy udało im się pomyślnie skontaktować z aplikacją, czy nie. Cała reszta jest w takich przypadkach często bardziej naturalnie komunikowana przy użyciu protokołu wyższego poziomu.
W każdym razie, niezależnie od tego, który z powyższych widoków preferujesz, jest kilka szczegółów, o których powinieneś pamiętać. Jednym z nich jest to, że w wielu przypadkach może istnieć znaczące rozróżnienie między (zasadniczo) pustym zasobem a nieistniejącym zasobem .
Na poziomie HTTP pusty zasób byłby po prostu oznaczony kodem 200 odpowiedzi i pustym ciałem odpowiedzi, natomiast nieistniejący zasób byłby wskazany przez odpowiedź 404 i treść zasobu wyjaśniającą brak zasobu. W protokole API wyższego poziomu zwykle wskazuje się na nieistniejący zasób za pomocą odpowiedzi na błąd, zawierającej odpowiedni kod / komunikat błędu specyficzny dla protokołu, natomiast pusta odpowiedź byłaby po prostu normalną strukturą odpowiedzi bez elementów danych.
(Zauważ, że zasób nie musi być dosłownie długi na zero bajtów, aby był „pusty” w sensie, o którym mowa powyżej. Na przykład wynik wyszukiwania bez pasujących elementów byłby liczony jako pusty w szerokim znaczeniu, tak jak wynik zapytania SQL z bez wierszy lub dokumentu XML nie zawierającego rzeczywistych danych).
Ponadto, oczywiście, jeśli aplikacja naprawdę nie wierzy, że żądana subresource powinno tam być, ale nie może go znaleźć, potem trzeci możliwy kod odpowiedzi istnieje:
500 Internal Server Error
. Taka odpowiedź ma sens, jeśli istnienie zasobu jest założonym warunkiem wstępnym aplikacji, tak że jego brak koniecznie oznacza wewnętrzną awarię.Wreszcie, należy zawsze pamiętać o prawie Postela :
Niezależnie od tego, czy serwer powinien odpowiedzieć w konkretnej sytuacji odpowiedzią 200, czy 404, nie usprawiedliwia to, jako implementatora klienta, odpowiedniej obsługi odpowiedzi w sposób maksymalizujący niezawodną interoperacyjność. Oczywiście można argumentować, co oznacza „odpowiednie” postępowanie w różnych sytuacjach, ale z pewnością nie powinno to normalnie obejmować awarii lub „rozpadu”.
źródło
Co powiesz na 204 No Content? Sugeruje to, że Twoje zapytanie zostało przetworzone pomyślnie, ale nic nie zwraca. To wciąż „sukces”, ale pozwala zobaczyć, czy masz wyniki oparte na samym kodzie stanu.
źródło
Jeśli adres URL reprezentuje zasób, który nigdy nie istniał, zwróć 404 Nie znaleziono
Jeśli adres URL reprezentuje zasób, który jest pustą listą, zwróć pustą listę i 200 OK.
Przykład:
Jeśli adres URL reprezentuje zasób, który kiedyś istniał, zwróć 410 Gone.
Odnośnie dialogu Lego Szturmowca:
źródło
Z tego dźwięku jest to interfejs API do użytku wewnętrznego . Daje to przewagę przy stosowaniu dowolnego schematu, który daje największe korzyści , niezależnie od tego, czy jest to zgodne z księgą (specyfikacja), czy nie. Nie oznacza to, że całkowicie wymyślisz własne kody statusu, ale możesz nieco „wygiąć” reguły, jeśli jest to korzystne.
Zgadzam się z twoim stanowiskiem, że powinieneś otrzymać kod statusu, który pokazuje, że coś poszło nie tak. Po to właśnie są kody stanu. Dostajesz także korzyści z bibliotek, które zgłaszają wyjątki / etc. na kodzie stanu innym niż 200, abyś nie musiał jawnie sprawdzać (Możesz też napisać własne opakowanie, które to robi).
Zgadzam się również z punktem widzenia Andresa F., że 500 jest odpowiednie, ponieważ drzewo powinno istnieć. W praktyce jednak lubię dzielić błędy serwera na dwie kategorie. Coś nieoczekiwanego poszło nie tak i coś, co mogę praktycznie sprawdzić, poszło nie tak. Powoduje to następujące kody stanu,
W twoim konkretnym przypadku możesz sprawdzić, czy drzewo istnieje po stronie serwera, a jeśli go nie ma, zwróć 409. Jest to oczekiwany błąd (wiesz, że może się zdarzyć, możesz to sprawdzić itp.) . Konflikt 409 to tylko moje osobiste preferencje, 5xx może być również odpowiedni, o ile możesz usiąść i zdecydować o tym ze swoim zespołem.
Kategoryzowanie takich kodów pomaga szybciej zidentyfikować rodzaj błędu, ale może przynieść korzyści poza organizacją. Często z błędami witryny nie chcesz, aby klient otrzymywał nieoczekiwane błędy, ponieważ może to powodować problemy związane z bezpieczeństwem i ujawniać luki w zabezpieczeniach, dlatego zwracany jest typowy błąd 500 „Wystąpił błąd”. i zaloguj pełny błąd na serwerze. Ale jeśli wystąpi oczekiwany błąd jako 409, wiesz, że bezpiecznie byłoby pokazać klientowi błąd i nie musisz zostawiać go w ciemności, co się stało. To tylko jedno praktyczne zastosowanie, które mogę opisać, ale istnieje wiele możliwości.
Jest to trochę kłopotliwe, ponieważ publikujesz to, ponieważ nie jesteś w stanie zgodzić się ze swoimi współpracownikami, ale brzmi to tak, jakbyście spierali się o semantykę i kto ma rację polityczną. Tak naprawdę nie ma znaczenia, kto jest bardziej odpowiedni, o ile można wymyślić system, który najbardziej przyniesie korzyści firmie.
Z drugiej strony, jeśli jest to publiczny interfejs API zgodny ze specyfikacjami tak blisko, jak to możliwe, ważniejsze byłoby uniknięcie zamieszania wśród społeczności.
źródło
Biorąc to pod uwagę: jeśli człowiek ostatecznie korzysta z API (poprzez GUI), sugerowałbym robienie czegokolwiek, co ułatwia życie użytkownikowi końcowemu. Nieistnienie drzewa, gdy powinno ono istnieć, jest błędem „niespójności modelu domeny”. Błąd systemowy występuje, gdy zabraknie pamięci lub wystąpi inna awaria systemowa. Dlatego zwracanie 5xx jest niewłaściwe. Jak wspomniano powyżej, 4xx może być odpowiednie, jeśli samo drzewo ma swój własny identyfikator URI, co nie ma miejsca w tym przypadku. Ale oto, co 404 mówi klientowi: możesz próbować raz za razem, dopóki coś nie odzyskasz. Jeśli zwróciłeś 200, możesz zwrócić wystarczającą diagnostykę z powrotem do użytkownika lub agenta użytkownika, aby agent użytkownika mógł wyświetlić pomiar, aby użytkownik przestał ponawiać próbę i obsługiwał tylko kontakty. Z drugiej strony, jeśli ten interfejs API jest przeznaczony tylko dla systemów,
źródło