2013-03-24 5 views
9

Welche Best Practices gibt es, um HTTP-Statuscodes in RESTful API zurückzugeben? Ich benutze Laravel 4 für mein PHP-Framework.Best Practice für Fehler in der RESTful-API

Im Falle eines Fehlers, sollte verwendet

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

oder

umfassen Flag für success

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

oder

Einsatz 200 anstelle von 4xx, auf success verlassen, um zu bestimmen, ob es ein Fehler ist

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

Und im Falle des Erfolgs, und es gibt keine Notwendigkeit, alle Daten zurück, kehren Sie noch etwas?

PHP API-Code

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? 
    } 
} 

Antwort

12

Wenn Sie an der list of available HTTP status codes schauen, Sie irgendwann erkennen, dass es viele von ihnen gibt, sondern verwendet allein können sie nicht wirklich einen Fehler von selbst erklären.

Um Ihre Frage zu beantworten, gibt es zwei Teile. Eine ist: Wie kann Ihre API die Gründe für einen Fehler kommunizieren und nützliche Informationen hinzufügen, die der Benutzer der API (der in den meisten Fällen ein anderer Entwickler ist) lesen und entsprechend handeln kann? Sie sollten so viele Informationen wie möglich hinzufügen, sowohl maschinenlesbar als auch lesbar.

Der andere Teil: Wie können HTTP-Statuscodes helfen, bestimmte Fehler (und Erfolg) Zustände zu unterscheiden?

Dieser letzte Teil ist tatsächlich härter als man könnte. Es gibt die offensichtlichen Fälle, in denen 404 verwendet wird, um "nicht gefunden" zu sagen. Und 500 für alle Fehler, die serverseitig sind.

Ich würde nicht den Status 401 verwenden, es sei denn, ich möchte den Vorgang erfolgreich ausführen, wenn HTTP-Authentifizierungsinformationen vorhanden sind. 401 löst normalerweise ein Dialogfeld im Browser aus, das schlecht ist.

Wenn eine Ressource eindeutig und bereits vorhanden ist, scheint der Status "409 Conflict" angemessen. Und wenn das Erstellen eines Benutzers erfolgreich ist, klingt der Status "201 Created" ebenfalls nach einer guten Idee.

Beachten Sie, dass es viel mehr Statuscodes gibt, einige von ihnen im Zusammenhang mit Erweiterungen des HTTP-Protokolls (wie DAV), einige völlig unstandardisiert (wie Status "420 Enhance your Ruhe" von der Twitter-API). Werfen Sie einen Blick auf http://en.wikipedia.org/wiki/List_of_HTTP_status_codes, um zu sehen, was bisher verwendet wurde, und entscheiden Sie, ob Sie etwas für Ihre Fehlerfälle angemessen verwenden möchten.

Aus meiner Erfahrung ist es einfach, einen Statuscode auszuwählen und zu verwenden, aber es ist schwierig, dies konsistent und in Übereinstimmung mit bestehenden Standards zu tun.

Ich würde jedoch nicht hier aufhören, nur weil andere sich beschweren könnten. RESTful Interfaces richtig zu machen ist eine schwierige Aufgabe, aber je mehr Interfaces vorhanden sind, desto mehr Erfahrung wurde gesammelt.

Edit:

In Bezug auf die Versionierung: Es ist eine schlechte Praxis betrachtet eine Version Tag in das URL zu setzen, etwa so: example.com/api/v1/stuff Es wird funktionieren, aber es ist nicht schön.

Aber die erste Sache ist: Wie legt Ihr Kunde fest, welche Art von Repräsentation er erhalten möchte, d. H. Wie kann er entscheiden, entweder JSON oder XML zu bekommen? Antwort: Mit dem Accept Header. Er könnte Accept: application/json für JSON und Accept: application/xml für XML senden. Er könnte sogar mehrere Typen akzeptieren, und der Server entscheidet dann, was er zurückgeben soll.

Wenn der Server nicht mit mehr als einer Darstellung der Ressource (JSON oder XML, vom Client ausgewählt) beantwortet wird, gibt es wirklich nicht viel Auswahl für den Client. Aber es ist immer noch eine gute Sache, wenn der Klient mindestens "application/json" als seine einzige Wahl sendet und dann als Antwort eine Kopfzeile Content-type: application/json zurückgibt. Auf diese Weise machen sich beide Seiten klar, was sie von der anderen Seite erwarten.

Jetzt für die Versionen. Wenn Sie die Version in die URL einfügen, erstellen Sie effektiv verschiedene Ressourcen (v1 und v2), aber in Wirklichkeit haben Sie nur eine Ressource (= URL) mit verschiedenen Methoden, um darauf zuzugreifen. Das Erstellen einer neuen Version einer API muss stattfinden, wenn die Parameter einer Anfrage und/oder die Darstellung in der Antwort, die mit der aktuellen Version inkompatibel ist, nicht geändert werden können.

Wenn Sie also eine API erstellen, die JSON verwendet, befassen Sie sich nicht mit generischem JSON. Sie beschäftigen sich mit einer konkreten JSON-Struktur, die in Ihrer API irgendwie einzigartig ist. Sie können und sollten dies in der vom Server gesendeten Content-type angeben. Die Erweiterung "Vendor" ist dafür da: Content-type: application/vnd.IAMVENDOR.MYAPI+json wird der Welt sagen, dass die grundlegende Datenstruktur application/json ist, aber es ist Ihre Firma und Ihre API, die wirklich sagt, welche Struktur zu erwarten ist. Und genau dort passt die Version für die API-Anfrage: application/vnd.IAMVENDOR.MYAPI-v1+json.

Anstatt die Version in die URL zu setzen, erwarten Sie, dass der Client eine Accept: application/vnd.IAMVENDOR.MYAPI-v1+json Kopfzeile sendet, und Sie antworten auch mit Content-type: application/vnd.IAMVENDOR.MYAPI-v1+json. Das ändert wirklich nichts für die erste Version, aber lass uns sehen, wie sich die Dinge entwickeln, wenn Version 2 ins Spiel kommt.

Der URL-Ansatz erstellt einen völlig unabhängigen Satz neuer Ressourcen. Der Client wird sich fragen, ob example.com/api/v2/stuff dieselbe Ressource wie example.com/api/v1/stuff ist. Der Client hat möglicherweise einige Ressourcen mit der API v1 erstellt und die URLs für dieses Material gespeichert. Wie soll er all diese Ressourcen auf V2 upgraden? Die Ressourcen haben sich wirklich nicht verändert, sie sind gleich, das einzige, was sich geändert hat, ist, dass sie in v2 anders aussehen.

Ja, der Server kann den Client möglicherweise benachrichtigen, indem er eine Weiterleitung an die v2-URL sendet. Eine Umleitung signalisiert jedoch nicht, dass der Client auch den Client-Teil der API aktualisieren muss.

Wenn Sie einen Accept-Header mit der Version verwenden, ist die URL der Ressource für alle Versionen identisch. Der Client entscheidet sich, die Ressource entweder mit Version 1 oder 2 anzufordern, und der Server ist möglicherweise so freundlich und beantwortet weiterhin Anfragen der Version 1 mit Antworten der Version 1, aber alle Anfragen der Version 2 mit den neuen und glänzenden Antworten der Version 2.

Wenn der Server eine Anforderung der Version 1 nicht beantworten kann, kann er den Client durch Senden des HTTP-Status "406 Not Acceptable" informieren (Die angeforderte Ressource kann nur Inhalte generieren, die gemäß den übermittelten Accept-Headern nicht akzeptabel sind) die Anfrage.)

Der Client kann den Accept-Header mit beiden Versionen senden, wodurch der Server mit demjenigen antworten kann, den er am liebsten hat, dh ein Smart-Client kann die Versionen 1 und 2 implementieren und sendet nun beide als Accept-Header und wartet für den Server, von Version 1 auf 2 zu aktualisieren. Der Server wird in jeder Antwort sagen, ob es Version 1 oder 2 ist, und der Client kann entsprechend handeln - er muss das genaue Datum des Serverversionsupgrades nicht kennen.

Um es zusammenzufassen: Für eine sehr grundlegende API mit begrenzten, vielleicht internen, kann sogar die Verwendung einer Version übertrieben sein. Aber man weiß nie, ob das in einem Jahr wahr ist. Es ist immer eine gute Idee, eine Versionsnummer in eine API aufzunehmen. Und der beste Punkt dafür ist innerhalb der Mime-Art, die Ihre API verwenden wird. Die Überprüfung auf die einzelne vorhandene Version sollte trivial sein, aber Sie haben die Möglichkeit, später transparent zu aktualisieren, ohne vorhandene Clients zu verwirren.

+0

Die Ruhe api ist nur für meine eigene Website Ajax/Backbonejs/Jquery zu verwenden. Sollte ich mich in diesem Fall an denselben Fehlercode halten (etwa 400)? Oder geben Sie 200 für jede AJAX-Antwort zurück und überprüfen Sie die 'success'-Variable, um zu sehen, ob ein Fehler aufgetreten ist. – Nyxynyx

+1

Nein, die grundlegende" Erfolg/Fehler "-Faktheit über einen Fehlercode ist eine sehr gute Idee. Fehlerantworten werden von HTTP-Clients unterschiedlich behandelt, z. Sie sollten nicht im Cache gespeichert werden. Das Gleiche in der Datennutzlast anzugeben, ist auch eine gute Sache. Meine eigene API hat entweder "Daten" für den Erfolg oder "Fehler" für den Fehler. Das ist im Grunde dasselbe wie "Erfolg = richtig/falsch", und es funktioniert für mich. Aber wissen Sie, dass der Status "400 Bad Request" nicht der generische Clientfehlerstatus ist, den Sie denken. Das gibt es nicht, Sie müssen den Fehlerstatus angeben. – Sven

+2

Große Antwort, Sven! Allerdings sagen Sie:> In Bezug auf Versionierung: Es ist eine schlechte Praxis, eine Version > Tag in die URL zu setzen, die ich nicht stimme. Hier ist ein [guide] (http://apigee.com/about/api-best-practices/restful-api-design-second-edition) von Apigee, der zu dem Schluss kommt, dass es tatsächlich die beste Methode ist, die Versionsnummer zu verwenden die URL Sie klären auch die Rückkehrstatuscodes. – unicopter

2

Ich würde 200 Status für alles nicht verwenden. Das wäre einfach verwirrend.

Jquery ermöglicht Ihnen, verschiedene Antwortcodes unterschiedlich zu verarbeiten. Es gibt bereits Methoden dafür, also nutzen Sie sie in Ihren Apps. Wenn Ihre App wächst, können Sie diese API auch anderen zur Verfügung stellen.

Edit: Ebenfalls sehr empfehle ich dieses Gespräch über Laravel und API Entwicklung zu beobachten:

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

+0

Der Video-Link ist hilfreich, aber der Redner macht einige schlimme Dinge, indem er eine REST-konforme API wie die Versionsnummer in der URL implementiert. Dafür gibt es den Header "Accept". – Sven

+0

@Sven Könnten Sie das bitte ausführlicher erklären, wie man das benutzt? Ich bin neugierig =) – msurguy

+0

Meine Antwort aktualisiert. – Sven

1

Es gibt einige Liste der HTTP-Statuscode an Illuminate\Http\Response, die Symfony\Component\HttpFoundation\Response verlängern. Sie können das in Ihrer Klasse verwenden.

Zum Beispiel:

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

es viel besser lesbar.