2013-03-24 7 views
9

Jakie są najlepsze praktyki dotyczące zwracania kodów stanu HTTP w RESTful API? Używam Laravel 4 do mojej struktury PHP.Najlepsze wskazówki dotyczące błędów w RESTful API

W przypadku wystąpienia błędu, należy użyć

return Response::json('User Exists', 401); 

lub

zawierać flagę success

return Response::json([ 
    'success' => false, 
    'data' => 'User Exists'], 
    401 
); 

lub

użytku 200 zamiast 4xx, powołując się na success celu ustalenia, czy doszło do błędu

return Response::json([ 
    'success' => false, 
    'data' => 'User Exists'], 
    200 
); 

A w przypadku powodzenia i nie ma potrzeby, aby powrócić żadnych danych, czy nadal nic powrócić?

PHP API Kod

public function getCheckUniqueEmail() { 
    // Check if Email already exist in table 'users' 
    $uniqueEmail = checkIfEmailExists(); 

    // Return JSON Response 
    if($uniqueEmail) { 
     // Validation fail (user exists) 
     return Response::json('User Exists', 401); 
    } else { 
     // Validation success 
     // - Return anything? 
    } 
} 

Odpowiedz

12

Kiedy patrzysz na list of available HTTP status codes, będzie w pewnym momencie sprawę, że istnieje wiele z nich, ale stosowany samodzielnie nie są w stanie tego wytłumaczyć błąd sama.

Więc, aby odpowiedzieć na twoje pytanie, są dwie części. Jednym z nich jest: w jaki sposób interfejs API może informować o przyczynach błędu i dodawać przydatne informacje, które użytkownik interfejsu API (który w większości przypadków jest innym programistą) może przeczytać i podjąć działania. Powinieneś dodać jak najwięcej informacji, zarówno do odczytu maszynowego, jak i czytelnych dla ludzi.

Druga część: W jaki sposób kody stanu HTTP mogą pomóc w rozróżnieniu pewnych stanów błędów (i powodzenia)?

Ta ostatnia część jest rzeczywiście trudniejsza niż jedna rzecz. Istnieją oczywiste przypadki, w których 404 jest używane do powiedzenia "nie znaleziono". I 500 dla wszelkich błędów, które są po stronie serwera.

Nie użyłbym statusu 401, chyba że naprawdę chcę zezwolić na operację, jeśli są obecne poświadczenia uwierzytelniania HTTP. 401 zwykle uruchamia okno dialogowe w przeglądarce, co jest złe.

W przypadku, gdy ressource jest unikalny i już istnieje, stan "409 Conflict" wydaje się odpowiedni. A jeśli tworzenie użytkownika powiedzie się, status "201 Stworzony" również brzmi jak dobry pomysł.

Należy pamiętać, że istnieje o wiele więcej kodów statusu, niektóre z nich są powiązane z rozszerzeniami protokołu HTTP (np. DAV), niektóre zupełnie niestandaryzowane (np. Status "420 Zwiększenie spokoju" z Twitter API). Spójrz na numer http://en.wikipedia.org/wiki/List_of_HTTP_status_codes, aby zobaczyć, co było używane do tej pory, i zdecyduj, czy chcesz użyć czegoś odpowiedniego dla swoich błędów.

Z mojego doświadczenia łatwo jest wybrać kod statusu i użyć go, ale trudno jest to zrobić konsekwentnie i zgodnie z istniejącymi standardami.

Nie zatrzymałbym się jednak tylko dlatego, że inni mogą narzekać. :) Robienie dobrych interfejsów RESTful jest samo w sobie trudnym zadaniem, ale im więcej interfejsów istnieje, tym więcej zebranych doświadczeń.

Edit:

chodzi wersjonowanie: Jest uważany za złą praktyką umieścić tag wersji do adresu URL, tak: example.com/api/v1/stuff Będzie działać, ale nie jest to miłe.

Ale najważniejsze jest: w jaki sposób klient określa, jakiego rodzaju reprezentacji chce uzyskać, tj. W jaki sposób może zdecydować się na uzyskanie JSON lub XML? Odpowiedź: z nagłówkiem Accept. Mógł wysłać Accept: application/json dla JSON i Accept: application/xml dla XML. Może nawet zaakceptować wiele typów i to do serwera należy decyzja, co zwrócić.

O ile serwer nie jest zaprojektowany do odpowiedzi na więcej niż jedną reprezentację zasobu (JSON lub XML, wybrany przez klienta), tak naprawdę nie ma dużego wyboru dla klienta. Ale nadal dobrze jest, aby klient wysłał co najmniej "application/json" jako swój jedyny wybór, a następnie w odpowiedzi odpowiedział nagłówkiem Content-type: application/json. W ten sposób obie strony dbają o to, czego oczekują od drugiej strony, aby zobaczyć treść.

Teraz wersje. Jeśli umieścisz wersję w adresie URL, skutecznie utworzysz różne zasoby (v1 i v2), ale w rzeczywistości masz tylko jeden zasób (= URL) z różnymi metodami dostępu do niego. Utworzenie nowej wersji interfejsu API musi nastąpić, gdy nastąpią zmiany w parametrach żądania i/lub reprezentacji w odpowiedzi, która jest niezgodna z aktualną wersją.

Kiedy więc tworzysz interfejs API wykorzystujący JSON, nie zajmujesz się standardowym JSON. Zajmujesz się konkretną strukturą JSON, która jest w jakiś sposób unikalna dla twojego API. Możesz i prawdopodobnie powinieneś o tym poinformować w przesłanym przez serwer Content-type. Dostępne jest rozszerzenie "sprzedawca": Content-type: application/vnd.IAMVENDOR.MYAPI+json powie światu, że podstawową strukturą danych jest aplikacja/json, ale to firma i interfejs API naprawdę mówią, jakiej struktury oczekiwać. I to jest dokładnie to, gdzie wersja dla żądania API pasuje do: application/vnd.IAMVENDOR.MYAPI-v1+json.

Zamiast umieszczać wersję w adresie URL, należy oczekiwać, że klient wyśle ​​nagłówek Accept: application/vnd.IAMVENDOR.MYAPI-v1+json, a także odpowiedzieć pod numerem Content-type: application/vnd.IAMVENDOR.MYAPI-v1+json. To naprawdę nic nie zmienia dla pierwszej wersji, ale zobaczmy, jak się rozwiną, gdy pojawi się wersja 2.

Podejście URL stworzy całkowicie niepowiązany zestaw nowych zasobów. Klient będzie się zastanawiał, czy example.com/api/v2/stuff jest tym samym zasobem co example.com/api/v1/stuff. Klient mógł utworzyć pewne zasoby za pomocą interfejsu API w wersji 1 i zapisał adresy URL dla tych plików. Jak powinien zaktualizować wszystkie te zasoby do wersji 2? Zasoby naprawdę się nie zmieniły, są takie same, zmieniło się tylko to, że wyglądają inaczej w v2.

Tak, serwer może powiadomić klienta, wysyłając przekierowanie do adresu URL v2. Ale przekierowanie nie oznacza, że ​​klient musi również zaktualizować część API klienta.

Podczas korzystania z nagłówka akceptującego w wersji, adres URL zasobu jest taki sam dla wszystkich wersji. Klient decyduje się zażądać zasobu z wersją 1 lub 2, a serwer może być tak dobry i wciąż odpowiada na żądania wersji 1 z odpowiedziami w wersji 1, ale wszystkie żądania wersji 2 z nowymi i błyszczącymi wersjami 2.

Jeśli serwer nie może odpowiedzieć na żądanie w wersji 1, może poinformować klienta, wysyłając stan HTTP "406 Not Acceptable" (Żądany zasób może generować treść niedopuszczalną zgodnie z przesłanymi nagłówkami Accept prośba.)

Klient może wysłać nagłówek akceptacji z obiema wersjami, co umożliwiło serwerowi odpowiedź z tym, który najbardziej mu odpowiada, tj. Inteligentny klient może implementować wersje 1 i 2, a teraz wysyła oba jako nagłówek akceptacji i czeka aby serwer mógł wykonać aktualizację z wersji 1 na 2. Serwer będzie informował w każdej odpowiedzi, czy jest to wersja 1 lub 2, a klient może działać odpowiednio - nie musi znać dokładnej daty aktualizacji wersji serwera.

Podsumowując: w przypadku bardzo prostego API z ograniczonym, może wewnętrznym, używaniem nawet wersji może być przesada. Ale nigdy nie wiesz, czy to będzie prawdą za rok. Zawsze dobrze jest dołączyć numer wersji do API. Najlepszym miejscem na to jest typ MIME, z którego ma korzystać Twój interfejs API. Sprawdzanie pojedynczej istniejącej wersji powinno być trywialne, ale masz możliwość przezroczystej aktualizacji później, bez mylenia istniejących klientów.

+0

Spokojne api jest przeznaczone tylko dla mojej ajax/backbonejs/jquery mojej witryny. W takim przypadku, czy powinienem po prostu trzymać się tego samego kodu błędu (powiedzmy 400)? Lub zwróć 200 dla każdej odpowiedzi AJAX i sprawdź zmienną 'success', aby zobaczyć, czy wystąpił błąd. – Nyxynyx

+1

Nie, wskazanie podstawowego faktu" sukcesu/błędu "za pomocą kodu błędu jest bardzo dobrym pomysłem. Odpowiedzi na błędy są obsługiwane przez klientów HTTP, np. nie powinny być buforowane itp. Wskazane jest to samo w ładowności danych. Mój własny interfejs API ma "dane" dotyczące sukcesu lub "błąd" po awarii. Jest to zasadniczo takie samo jak "success = true/false" i działa dla mnie. Ale wiem, że status "400 Złych żądań" nie jest ogólnym stanem błędu klienta, który Twoim zdaniem jest. Nie ma czegoś takiego, musisz określić status błędu. – Sven

+2

Świetna odpowiedź, Sven! Mówisz jednak:> W odniesieniu do wersjonowania: Uważa się, że niewłaściwa praktyka jest umieszczanie znacznika wersji > w adresie URL, z którym nie zgadzam się. Oto [przewodnik] (http://apigee.com/about/api-best-practices/restful-api-design-second-edition) od Apigee, który stwierdza, że ​​* jest * rzeczywiście najlepszą praktyką używania numeru wersji w adres URL. Wyjaśniają również kody statusu powrotu. – unicopter

2

Nie użyłbym 200 statusu do wszystkiego. To byłoby po prostu mylące.

Jquery umożliwia przetwarzanie różnych kodów odpowiedzi w inny sposób, istnieją wbudowane metody, dzięki którym można już korzystać z nich w swoich aplikacjach, a gdy aplikacja będzie się rozwijać, można udostępnić interfejs API innym użytkownikom.

Edit: Również bardzo polecam oglądania tego mówić o laravel i rozwoju API:

http://kuzemchak.net/blog/entry/laracon-slides-and-video

+0

Łącze do pliku wideo jest pomocne, ale głośnik robi złe rzeczy, implementując RESTful API, np. Mając numer wersji w adresie URL. Do tego służy nagłówek "Zaakceptuj". – Sven

+0

@ Czy mógłbyś wyjaśnić bardziej szczegółowo, jak tego użyć? Jestem ciekawy =) – msurguy

+0

Zaktualizowano moją odpowiedź. – Sven

1

Istnieją pewne lista kod stanu HTTP na Illuminate\Http\Response, które rozciągają się do Symfony\Component\HttpFoundation\Response. Możesz go użyć w swojej klasie.

Na przykład:

use Illuminate\Http\Response as LaravelResponse; 
... 
return Response::json('User Exists', LaravelResponse::HTTP_CONFLICT); 

jest dużo bardziej czytelny.