Czy „Brak wyników” powinno być błędem w odpowiedzi RESTful?

52

Opiszę przykład:
Zaczynam tworzyć API dla piekarni. Interfejs API pozwoli użytkownikom przeszukiwać katalog w poszukiwaniu produktów do pieczenia, takich jak domowe domowe ciasteczka z miętowymi kawałkami czekolady api.examplebakery.com/search?q=......

Ktoś używa tego, aby wyszukać produkt o nazwie pineapple-banana flavoured cookiesi oczywiście nie znajdzie żadnych wyników.

Czy należy to zwrócić jako błąd? Wyszukiwanie nie zakończyło się niepowodzeniem, interfejs API przeszukał i pomyślnie stwierdził, że nie można znaleźć plików cookie. Interfejs API nie powinien zwrócić 404, ponieważ interfejs API został rzeczywiście znaleziony.

Berry M.
źródło
51
204 Brak treści
AakashM
6
Możliwy duplikat RESTful API reprezentuje brak czegoś
gnat
3
@gnat: To nie jest duplikat, ponieważ drugie pytanie dotyczy określonego zasobu, a nie zapytania dotyczącego wielu zasobów.
Greg Burghardt,
7
Analogicznie załóżmy, że masz funkcję, która zwraca tablicę obiektów. Jeśli nie ma żadnych obiektów, które pasowałyby do konkretnego przypadku użycia, czy wolisz tę funkcję przez wyjątek, czy zwracasz pustą tablicę?
Kevin - Przywróć Monikę
2
@AakashM Zwracanie HTTP-204 do żądania GET jest dość niezwykłe, wiem, że nigdzie go nie widziałem. O ile mi wiadomo, HTTP-204 jest zwykle używany jako odpowiedź podczas modyfikowania zasobu na serwerze, na przykład żądania POST / PUT / DELETE.
Radu Murzea,

Odpowiedzi:

122

Gdy są wyniki, wynikiem jest lista (JSON, na podstawie twojego komentarza). W przypadku zapytań bez wyników dane wyjściowe powinny być dokładnie takie same. Lista prosta zawiera 0 pozycji.

Więc jeśli twoja odpowiedź brzmi zwykle:

{
    "results": [
        {
            "name": "Pancakes",
            ....
        },
        {
            "name": "French Fries",
            ....
        }
    ]
}

Następnie dla zapytania z 0 wynikami powinno być to:

{
    "results": []
}

Jeśli dołączysz również metadane dotyczące liczby „stron” wyników, linki do tych „stron” itp., Sugeruję, aby powiedzieć, że istnieje 1 „strona”.

Status HTTP powinien być taki sam, jak w przypadku wyników - 200 OK.

204 No Contentmoże również wydawać się opcją, ale nie dlatego, że w rzeczywistości zwracasz „treść” - pustą listę. Jeśli uważasz, że pusta lista nie liczy się jako „treść”, co jeśli zmienisz odpowiedź, aby zaoferować sugestie dotyczące pisowni? Trzon odpowiedzi nadal będzie pustą listą, ale teraz jest jeszcze więcej „treści”.

Aby uzyskać bardziej przydatne informacje o kodach stanu HTTP, jpmc26 warto przeczytać ich odpowiedź .

Jory Geerts
źródło
9
Jest to ten sam sposób myślenia, co wzorzec zerowego obiektu . Błędy i zero to nie jedyny sposób na stwierdzenie, że nic tu nie ma. Czasami chcesz cicho wyrazić swoje nic. W ten sposób klienci nie muszą nic testować.
candied_orange
54
Twierdzę, że zwracanie 204 jest niewłaściwe, ponieważ zwracasz treść. Po prostu treść nie ma żadnych wyników, co różni się od jej braku.
TMN
9
@TMN zgodził się - 204 nie jest odpowiednie dla „brak wyników”. Twoje zapytanie powinno zawsze zwracać tablicę z wynikami w tablicy. Jeśli nie ma wyników, klient zajmie się tym w naturalny sposób. Jeśli klient chce wyświetlić specjalny tekst („Nie znaleziono wyników”), to w porządku. 204 należy zwrócić tylko dla punktu końcowego, który naturalnie nie zwraca wyniku.
JasonB
1
Możesz użyć 204, jeśli zwracałeś null zserializowany jako pusty ciąg, który rekonstruuję
Ewan
15
To. Ważną rzeczą przy tworzeniu RESTful API jest część API, a nie spokój. Dobry interfejs API ułatwia życie klientom / konsumentom. Pusta tablica jest łatwiejsza w obsłudze niż wartości zerowe / wyjątki / kody stanu.
Guran
37

Przy podejmowaniu decyzji o kodzie HTTP należy zawsze zadać następujące pytanie:

Co może / będzie / powinien zrobić dowolny klient z odpowiedzią?

  1. Czy klient powinien zawsze traktować odpowiedź jako niepowodzenie? Następnie chcesz 4xx lub 5xx, w zależności od tego, czy problemem są dane wejściowe klienta, czy procesy serwera.
  2. Czy zamiast tego klient powinien złożyć wniosek w innym miejscu? Zatem 3xx jest dla Ciebie.
  3. Czy serwer zrobił to, o co prosił klient (sukces)? To jest 2xx.

Zawsze decyduj, w którym zakresie powinien znajdować się kod odpowiedzi. Takie działanie szybko eliminuje wiele kodów odpowiedzi jako opcji i (co ważniejsze) znacznie ułatwia przestrzeganie semantyki kodów. Zobacz początkowe sekcje dokumentacji kodu HTTP, aby uzyskać wyjaśnienia dotyczące tego, co reprezentuje każda kategoria kodów.

W takim przypadku klient poprosił o listę wyników z filtrem z ważnego, istniejącego punktu końcowego i ma uprawnienia do uzyskania do niego dostępu. Serwer był w stanie przetworzyć żądanie i określić odpowiednie dane do zwrócenia (brak elementów), więc żądanie zakończyło się powodzeniem. Zdarza się, że filtr, który podali, odfiltrowuje wszystkie wyniki. Serwer nie powinien określać, czy tego właśnie chciał klient, czy nie, ponieważ może to być oczekiwany wynik dla niektórych klientów. Jeśli jest to w jakiś sposób problem z kodem klienta, to do obowiązków klienta należy określenie, sprawdzenie i odpowiednia obsługa. Więc to wyraźnie 2xx.

Teraz pytanie brzmi: „Które 2xx?” Zależy to od tego, jak zamierzasz odpowiedzieć na serwer.

  • Czy odeślesz reprezentację pustej listy, jak opisują niektóre inne odpowiedzi ? Jeśli tak, to chcesz 200. 200 oznacza, że ​​serwer nie napotkał żadnych problemów i ma reprezentację wyników do wykorzystania przez klienta. Jest to prawdopodobnie najwygodniejszy sposób odpowiedzi dla Twoich klientów, którzy mogą po prostu przeanalizować odpowiedź, niezależnie od tego, czy były wyniki, czy nie, a następnie wymyślić, jak samodzielnie obsłużyć pustą listę.
  • 204 nie jest tutaj semantycznie błędny, ale musiałbyś odpowiedzieć bez treści wiadomości . Oznacza to, że cały kod klienta musiałby jawnie sprawdzać różne kody HTTP (lub przynajmniej brak treści wiadomości) i obsługiwać je osobno. Jest to niewygodne i bardziej prawdopodobne, że prowadzi do źle wychowanych klientów.

Pozostałe nie mają zastosowania:

  • 201 nie wchodzi w rachubę. Nie utworzyłeś żadnych trwałych zasobów i nie zwracasz lokalizacji do utworzonego zasobu.
  • 202 nie wchodzi w rachubę. Żądanie zostało wykonane; nie przetwarza w tle.
  • 203 oznacza, że ​​odpowiedź została zmodyfikowana między autorytatywnym serwerem a klientem. Twój interfejs RESTful jest autorytatywnym serwerem, więc nie dotyczy to tutaj.
  • 205 nie ma sensu. Klient nie musi niczego usuwać ani odświeżać.
  • Wydaje się, że 206 jest przeznaczony do zwracania dużego zasobu po wielu odpowiedziach. Wymaga to również, aby klient poprosił o część treści w nagłówkach (więc paginacja za pomocą ciągów zapytań nie kwalifikuje się). Nie dotyczy tutaj.

Powinien więc wynosić 200 lub 204, a 200 częściej prowadzi do prostszego, bardziej niezawodnego kodu klienta (szczególnie jeśli używasz spójnej struktury odpowiedzi zawierającej pustą listę).

jpmc26
źródło
5
Byłbym zainteresowany opinią downvotera. Nie sądzę, żeby to wszystko było kontrowersyjne.
jpmc26
2
Nie sądzę, aby klienci musieli jawnie sprawdzać 204. Wszystko czego potrzebują to umiejętność obsługi obiektu odpowiedzi zerowej. Zadaniem frameworka HTTP jest obsłużenie 204 poprzez pominięcie części „parsowanie treści”. 200 z Content-Lenght 4 i body null jest dokładnie takie samo.
Agent_L,
1
@Agent_L Masz rację, że jeśli serwer odpowiada strukturą niespójną z normalną odpowiedzią (np. Umieszczenie nulltam, gdzie zwykle jest lista), nie będziesz czerpać korzyści z spójności nawet przy 200. Jednak to, co opisuję, to użycie odpowiedź, która jest zgodna z normalną strukturą i ma pustą listę, do której zwykle trafia lista wyników. 204 odbiera każdą okazję do uzyskania tak konsekwentnej odpowiedzi. Ponadto nawet w bibliotekach klienta HTTP, które mają dla niego funkcje wygody, często (zwykle?) Musisz wykonać jawne wywołanie w celu przeanalizowania JSON.
jpmc26
@Agent_L W szczególności w przypadku list wywołujący często mogą po prostu pozwolić, aby ich kod działał normalnie na pustej liście (na przykład przez zapętlanie go), podczas gdy potrzebowaliby jakiegoś jawnego sprawdzenia, aby obsłużyć inny rodzaj reprezentacji.
jpmc26,
16

Nie. Użycie 404 do wskazania „Twoje zapytanie zostało przetworzone, ale nie znaleziono żadnych dopasowań” jest okropne, ponieważ:

  • przepływ warunkowy oparty na obsłudze wyjątków (tj. zmuszanie do uzyskania wyjątkowego wyniku w celu utworzenia i obsługi wyjątku w kliencie, który może nie być wydajny i niewygodny)

  • nie znaleziono niejednoznaczności między „prawdziwą” stroną, wpisano błędne punkty końcowe

Należy pamiętać, że zawsze jest klient, który dokonuje deserializacji wiadomości i to, co klient zwraca, jest ważne; nie serializacja.

Jeśli klient powinien zwrócić null, użyj serializacji null. Jeśli klient zwróci pustą tablicę, użyj [], jeśli klient zgłosi błąd, użyj 500 i przekaż komunikat o błędzie

Ewan
źródło
2
Dlaczego serwer powinien dbać o to, co klient robi z informacjami? (PS: Nie jestem tym, który zlekceważył twoją odpowiedź).
Radu Murzea,
w tym kontekście „klient” to kod działający na urządzeniu klienckim, który udostępnia usługę aplikacji klienckiej. Musi być w stanie ujawnić metody usług i zwrócić wyniki zgodnie z zamierzeniami usługi. Potrzebujesz pary klient-serwer, aby komunikacja w ogóle działała
Ewan
3
Oczywiście nie używaj 5xx dla błędów klienta . W takim przypadku wolisz 4xx.
Kevin
1
Chociaż nie powinien to być „serwer”, a nie „klient” w większości tych przypadków? To serwer przetwarza żądanie i podaje odpowiedź, klient po prostu przetwarza odpowiedź? W takim przypadku kod 5xx byłby OK, ponieważ jest to błąd serwera, a nie błąd klienta?
MrWhite
2
Problem ze wszystkimi kodami błędów polega na tym, że mają one znaczenie w http. 500 to jedyny kod, który jest odpowiedni, gdy twoja usługa zgłasza wyjątek
Ewan
9

Bardzo dobra odpowiedź Beyond @ Ewan:

Jeśli zapytanie jest rodzajem, który zwraca zestaw wyników, wówczas pusty zestaw jest logicznie tak samo odpowiedni jak zestaw jednego lub zestawu więcej. Mówiąc ogólnie, z powodów, które stwierdza @Ewan, zmiana pustego zestawu na błąd jest bardziej szkodliwa niż pożyteczna i jest po prostu niepotrzebna.

Jeśli zapytanie jest rodzajem, który wyszukuje i zwraca określony singleton (który ma zostać znaleziony, np. Dokładne dopasowanie według identyfikatora), wówczas nie można znaleźć logicznie odpowiedniej możliwej odpowiedzi.

Erik Eidt
źródło
tak, dokładnie tak myślałem w odpowiedzi Ewana.
Walfrat
5

Zakładasz, że kod musi podjąć specjalne działanie, gdy nie zostaną zwrócone dane, ale może nie być tak. Kod może po prostu szukać liczby produktów lub dołączać wyniki do listy lub dowolnej liczby rzeczy. Powinieneś dawać użytkownikowi „błąd” tylko wtedy, gdy rzeczywiście wystąpił błąd.

John Smith
źródło
3
„Powinieneś dawać użytkownikowi„ błąd ”tylko wtedy, gdy rzeczywiście wystąpił błąd.” - to. Puste wyniki ustawione podczas wykonywania „wyszukiwania” zwykle nie są „błędem”. Jeśli jednak połączenie z bazą danych nie powiedzie się, co oznacza, że ​​wyszukiwanie nie może być faktycznie wykonane, wówczas pusty zestaw wyników (i bez błędu) byłby w przeciwnym razie niejednoznaczny. W tym przypadku odpowiedni byłby pewien rodzaj błędu (być może wraz z pustym zestawem wyników - w zależności od definicji API).
MrWhite
0

Gdy korzystam z interfejsu API, jako klient muszę obsługiwać przypadki „sukcesu” inne niż przypadki „błędu”; Nie mam tam wyboru. Dlatego powinieneś zwrócić błąd w sytuacjach, które klient chce traktować inaczej, i powodzenia w sytuacjach, które klient chce traktować tak samo.

Jeśli wykonam zapytanie, które teoretycznie może zwrócić dowolną liczbę wyników, zero, jeden, dwieście i tak dalej, powinieneś zwrócić „sukces”, ilekroć API dostarcza pełną listę wszystkich wyników. I być może w przypadkach, gdy istnieje wiele wyników, zwrócono częściową listę wyników, aby uniknąć nadmiernego rozmiaru, i istnieje uzgodniony sposób, w jaki mógłbym uzyskać inne wyniki. Jest tak, ponieważ jako klient często chcę obsługiwać przypadek zerowych wyników, tak jak przypadek większej liczby wyników. Mogę potraktować to inaczej, ale nie chcę być do tego zmuszany.

Inaczej jest w przypadku, gdy szukam wartości. Oczekuję dokładnie jednego wyniku, wartości, której szukam. Potrzebuję tego jednego rezultatu, aby kontynuować to, co chcę robić w znaczący sposób. Tutaj o wiele bardziej dopuszczalne jest zwrócenie statusu 404 dla przypadku, w którym nie ma żadnej wartości, ponieważ i tak muszę inaczej traktować tę sprawę.

Podsumowanie: Jeśli klient oczekuje dowolnej liczby wyników, od zera do dużych liczb, zwróć „sukces”, jeśli wszystkie wyniki zostaną dostarczone, nawet jeśli liczba jest równa zero. Jeśli klient oczekuje dokładnie jednego wyniku, zwróć sukces, jeśli wynik zostanie znaleziony, i błąd, jeśli wynik nie zostanie znaleziony.

gnasher729
źródło