Wyobraź sobie interfejs API pozwalający ustalić, czy dana osoba wybrała zwierzę duchowe. Mogą mieć tylko zero lub jeden duchowy zwierzak.
Obecnie:
/person/{id}/selectedSpiritAnimal
po wybraniu zwierzę zwraca http 200 i {selectedAnimal:mole}
ale gdy nie mają wyboru, zwraca http 404.
To sprawia, że moje zwierzę duchowe jest nieszczęśliwe, ponieważ reprezentujemy ważny problem związany z domeną - nie wybrałem jeszcze zwierzęcia duchowego - jako błąd HTTP.
Ponadto, jako firma - erm Sprit-Animal-Hampers-R-us - chcemy wiedzieć, kiedy ktoś nie ma wyboru, abyśmy mogli go o to poprosić.
Jaka jest lepsza odpowiedź tutaj:
HTTP 200 i {selectedAnimal:null}
lub nawet bardziej wyraźnie
HTTP 200 i {selectedAnimal:null, spiritAnimalSelected: false}
A może lepiej jest zwrócić 404? Ponieważ podobnie jak this image has not yet been uploaded
podczas oglądania obrazu w trybie online byłoby 404. this person has not selected a spirit animal
może być 404
To pytanie zostało zaproponowane jako duplikat, ale pytanie to dotyczy innego ważnego adresu URL wymaganego, gdy aplikacja została skonfigurowana tak, aby nie zezwalać na zmianę reprezentowaną przez adres URL.
Podczas gdy tutaj patrzę, jak reprezentuje się zasób, w którym brak zasobu jest znaczący. Oznacza to, że klient może zażądać adresu URL, a odpowiedź brzmi: pomyślnie zażądałeś zasobu, który reprezentuje brak jakiejś rzeczy.
Więc to nie jest „logika biznesowa”, ale raczej okoliczność, w której brak czegoś ma znaczenie (może być tak, jak wielu moich kolegów twierdzi, że 404 jest nadal poprawne), ale nie jestem pewien, jak odwzorować to na spec.
Bardzo trudno jest wybrać odpowiedź. Wielokrotnie zmieniałem zdanie na temat rozmowy tutaj i tej trwającej w pracy.
Rzeczą, która mnie tu rozlicza, jest to, że specyfikacja mówi, że 4xx jest wtedy, gdy klient się pomylił . W tym przypadku klientowi powiedziano, aby oczekiwał odpowiedzi z wybranego adresu URLSpiritAnimal, więc nie popełnił błędu.
Konsensus wśród moich kolegów jest taki, że jest to objaw złego projektu API
Prawdopodobnie byłoby lepiej, gdybyśmy po prostu poprosili / person / {id}, a to zwróci zestaw relacji linków dla tej osoby ... to jeśli nie otrzymasz linku / selectedSpiritAnimal (gdy dana osoba nie ma wyboru), ale ty nazwij to mimo to, wtedy 404 ma sens. Lub że implementujesz częściowe odpowiedzi i pozwalasz / person / {id} zwrócić pełniejszy dokument, chyba że klient zażąda podzbioru danych
Odpowiedzi:
Kody HTTP 4xx prawdopodobnie nie są właściwym wyborem dla tego scenariusza. Oświadczasz, że posiadanie zerowych zwierząt-duchów jest prawidłowym stanem, a trasa API
person/{id}/selectedSpiritAnimal
uwzględnia, czy dana osoba jeid
ma, czy nie.Odpowiedzi HTTP 4xx są zarezerwowane na sytuację, w której klient zrobił coś nieprawidłowego w żądaniu (patrz archiwum oryginalnej specyfikacji w3 ). Ale klient składa prawidłowe żądanie, niezależnie od tego, czy dana osoba
id
ma zwierzę duchowe.Dlatego skłaniam się ku drugim rozwiązaniom, używając odpowiednio sformatowanej treści JSON w odpowiedzi i kodu HTTP 2xx.
Teraz, jeśli otrzymasz taką prośbę i okaże się, że osoba
id
nie istnieje, kod 4xx ma większy sens.źródło
cases in which the client seems to have erred
, ale z drugiej strony 404 mówi wprostThe server has not found anything matching the Request-URI
. Możesz rozważyć żądanie czegoś, co nie jest błędem klienta. Rozumiem, że osoba nie istnieje, a nie ma podpory pomocniczej, ale może to być wskazane jako komunikat odpowiedzi. 204 wydaje się również istotne, ponieważ jednostka istnieje, ale nie ma treści dla pod własności.Pozwól, że przedstawię ci model dojrzałości Richardsona .
Twój problem polega na tym, że reprezentujesz dwa zasoby jako jeden, w którym tak naprawdę powinieneś mieć dwa zasoby, których relacje są wskazane przez hipermedia. Używanie hipermedii do opisywania związków to wspaniały poziom 3 Odpoczynku.
Twoja osoba powinna żyć pod URI,
/person/{id}
a zwierzę powinno żyć/spiritanimal/{id}
. Osoba powinna wskazać, że ma zwierzęcia duchowego, używając linku do zwierzęcia.Wyobraźmy sobie osobę o imieniu Bob, która ma identyfikator 123 i zwierzęce duchy Jednorożca.
GET /person/123
wróciłby;
Teraz każdy, kto czyta osobę 123, będzie wiedział, że ma duchowe zwierzę i ma identyfikator URI, w którym może uzyskać więcej informacji na jego temat.
GET /spitiranimal/789
może wrócić
Teraz wyobraźmy sobie osobę o imieniu Fred, która ma identyfikator 456 i nie ma zwierzęcia-ducha.
GET /person/456
wróciłby;
Teraz każdy, kto czyta osobę 456, będzie wiedział, że nie ma duchowego zwierzęcia, ponieważ nie ma linku. Nie ma potrzeby używania żadnego kodu stanu HTTP, który reprezentuje brak relacji.
źródło
To jest odpowiedni adres URL do pozyskiwania duchowych zwierząt; dlatego błąd 404 jest nieodpowiedni. 404 oznacza problem techniczny, a nie logiczny.
Właściwym rozwiązaniem jest zwrócenie http 200 i
{"selectedAnimal": null}
Powinieneś mieć oddzielna WebMethod
/person/{id}/hasSelectedSpiritAnimal
która zwraca{"isSpiritAnimalSelected": false}
. Za kulisami może, ale nie musi, wykonywać tych samych wywołań metod, po prostu zwraca wartość false, jeśli jest pusta, ale to zależy od decyzji, a nie od konsumującego kodu.Lepiej jest unikać łączenia oddzielnych zapytań w jedną metodę internetową bez ważnego powodu, nawet jeśli zapytania są ściśle powiązane.
źródło
When you said "the spirit animal is not currently on file", it seemed quite similar to me to "there is no content"
Brak treści oznacza brak treści . tzn .: zwraca „”. Te dwa wcale nie są podobne. „zwierzę duchowe nie jest aktualnie przechowywane” różni się bardzo od „”.To, co reprezentuje twój punkt końcowy, to nie tylko zwierzę; to zwierzę lub jego brak. Jest to wartość najlepiej reprezentowana przez
Optional
/Maybe
/Nullable
/ itp.Tak więc prawidłowe wartości (jak w przypadku 200 OK) mogą być:
{'animal': <some animal>, 'selected': true}
{'animal': null, 'selected': false}
Mogę sobie wyobrazić, że ta
DELETE
metoda, zastosowana do punktu końcowego, może ustawić'selected'
sięfalse
ponownie, czyli rozbroić wybrane zwierzę.Możesz oczywiście upuścić
'selected'
klucz tutaj, jest pokazany tylko dla jasności; ciąg vsnull
jest wystarczający do rozróżnienia.źródło
Powinieneś użyć 404.
Ponieważ tworzysz interfejs programistyczny, a nie ludzki, tekst 404 jest opcjonalny.
Wolę to, ponieważ najbardziej preferuję standardowe protokoły. HTTP ma sposób reprezentowania nieistnienia i właśnie tego bym użył.
EDYCJA: Załóżmy, że dodałeś funkcję, w której użytkownicy mogą decydować, czy udostępnić swoje duchowe zwierzęta, a ktoś tego nie udostępnił. Czy zwrócisz 200 OK
null
, czy 200 OK"Unauthorized
? A może użyłbyś standardowego 401 Nieautoryzowanego / 403 Zabronionego? Wydaje się to wprost analogiczne do tego, aby nie wybierać jednego.Alternatywnie, jeśli chcesz użyć 200 OK + JSON, powinieneś wrócić
null
.Utrzymuj wszystko w czystości. Utwórz więcej opakowań tylko w razie potrzeby.
źródło
null
(nie mają wartości). Różni się to od tego, że klient żąda czegoś, dla którego nie istnieje gniazdo do przechowywania wartości. Nie sugerowałbyś wrzucaniaAttributeError
Pythona, gdy zdarza się, że jest to wartośćNone
; sprawiłoby to, że interfejs byłby niepraktyczny i niepotrzebnie trudny w obsłudze. Bardziej pragmatycznie, wiele interfejsów API klienta HTTP może przekonwertować 404 na standardowy mechanizm obsługi błędów języka (kod błędu, wyjątek, typ błędu), co oznacza, że będziesz musiał wyeliminować dodatkowy błąd./person/{id}/selectedSpritAnimal
Obserwować literówkęSprit
)./person/{id}/isSpiritAnimalSelected
który poinformuje klienta, czy zwierzę zostało wybrane. Wydaje mi się, że ten sam klasyczny przykład testowania, czy plik istnieje przed jego odczytaniem. Wystarczy przeczytać plik i obsłużyć błąd ENOENT, jeśli zostanie zgłoszony./person/{id}/selectedSpiritAnimal
należy go używać, nawet jeśli zwierzę duchowe nie istnieje. Oznacza to, że HTTP 4xx jest niepoprawny, jeśli zostanie użyty w takim przypadku. Op również poprawnie stwierdza, że może to być zapach złego projektu API.