RESTful API Design. Was soll ich zurückgeben, wenn keine Zeilen vorhanden sind?

50

Ich programmiere gerade eine API für ein soziales Netzwerk mit dem Slim Framework. Meine Frage lautet: Was sind die Best Practices, wenn in der json-Struktur keine zurückzugebenden Zeilen vorhanden sind?

Nehmen wir an, dass dieser Aufruf von / v1 / get / movies 2 Zeilen aus den Filmnamen der Tabelle zurückgibt:

[
    {"name": "Ghostbusters"},
    {"name": "Indiana Jones"}
]

Aber dann rufe ich / v1 / get / books auf und die Tabelle enthält keine Zeilen. Soll ich nur eine leere Struktur zurückgeben?

[
]

... oder wäre es besser eine Meldung und einen Fehlercode?

[
    "errors": {
        "message": "no matches found",
        "code": 134
    }
]

Was ist eine bessere Praxis? (Die API wird in iOS- und Android-Apps verwendet.) Vielen Dank!

Andres SK
quelle
3
Für mich ist das die Frage, ob Null tatsächlich ein Betrag ist.
scarfridge
16
Dein Beispiel ist gebrochen. Sie können keine JSON-Objekte mit doppelten Schlüsseln haben. Was Sie suchen, ist ein Array, dh[{"name": "..."}, {"name":"..."}]
Martin Wickman
@MartinWickman Entschuldigung, ich habe es gerade behoben.
Andres SK
8
@andufo, eigentlich hast du nicht ...
29.
25
Wenn Ihre Anwendung REST-fähig sein soll, warum wird das Verb / die Methode dann Teil Ihres Endpunkt-URI?
user50849

Antworten:

46

Normalerweise würde ich die Anzahl der Datensätze im Ergebnis als Metadaten zurückgeben. Ich bin mir nicht sicher, ob dies eine normale REST-Praxis ist, aber es handelt sich nicht um viele zusätzliche Daten und es ist sehr genau. Normalerweise gibt es eine Paginierung für viele Dienste. Es ist unpraktisch, eine große Ergebnismenge auf einmal zurückzugeben. Persönlich ärgere ich mich, wenn es Paginierung für kleine Ergebnismengen gibt. Wenn es leer ist, kehre zurück number_of_records : 0und buche als leere Liste / Array books : [].

{
    meta: {
        number_of_records : 2,
        records_per_page : 10,
        page : 0
    },
    books : [
        {id:1},
        {id:27}
    ]
}

BEARBEITEN (einige Jahre später): Antwort von Martin Wickman ist viel besser, hier ist "kurz" eine Erklärung warum.

Beachten Sie beim Umgang mit Paginierung immer die Möglichkeit von Inhalten oder Bestelländerungen. Wie kommt die erste Anfrage, 24 Ergebnisse, Sie geben zuerst 10 zurück. Danach wird "neues Buch" eingefügt und Sie haben jetzt 25 Ergebnisse, aber mit der ursprünglichen Anfrage würde es an 10. Stelle bestellt. Wenn der erste Benutzer die zweite Seite anfordert, erhält er kein "neues Buch". Es gibt Möglichkeiten, solche Probleme zu lösen, beispielsweise die Angabe einer "Anforderungs-ID", die mit folgenden API-Aufrufen gesendet werden soll, und die Rückkehr zur nächsten Seite aus der "alten" Ergebnismenge, die irgendwie gespeichert und an die "Anforderungs-ID" gebunden werden soll. Alternativ können Sie ein Feld wie "Ergebnisliste seit der ersten Anforderung geändert" hinzufügen.

Wenn Sie können, versuchen Sie im Allgemeinen, zusätzliche Anstrengungen zu unternehmen und Paginierung zu vermeiden. Paginierung ist ein zusätzlicher Zustand, der mutiert werden kann, und das Verfolgen solcher Änderungen ist fehleranfällig, zumal sowohl der Server als auch der Client damit umgehen müssen.

Wenn Sie zu viele Daten auf einmal verarbeiten möchten, sollten Sie erwägen, "id list" mit allen Ergebnissen und Details für einen Teil dieser Liste zurückzugeben und API-Aufrufe multi_get / get_by_id_list für resource bereitzustellen.

grizwako
quelle
1
Huh, ich frage mich, warum dieser nicht so hoch gewählt ist wie der andere. Mir gefällt dies besser, da es sowohl eine leere Liste (die eigentlich eine Liste sein sollte, oder?) Enthält, über die Sie blind ohne besondere Bedingungen iterieren können, als auch Metadaten, um zu sagen: "Nein, das haben wir nicht". t einen Fehler für Sie beschönigen, es gab tatsächlich 0 Ergebnisse ".
Izkata
1
-1, da der booksParameter ein Objekt ist, "books" jedoch mehr als eins und mehr als eins ein Array impliziert. Die Metadaten sind cool und alles andere als letztendlich würde ich erwarten, dass eine Sammlung von Büchern eine Reihe von Buchobjekten ist; Wenn es keine Bücher gibt, gib mir einfach das leere Array
Charles Sprayberry
9
Das Problem dabei ist, dass das Hinzufügen von "number_of_records" keine weiteren Informationen liefert, sondern lediglich Redundanz hinzufügt und die Komplexität erhöht. Um einen Fehler zu signalisieren, geben Sie einen geeigneten http-Code + etwas im Körper zurück.
Martin Wickman
1
@cspray books ist Liste, wie Izkata zeigte, mein Tippfehler.
Grizwako
2
@MartinWickman Ich wollte die ursprüngliche Antwort nicht mit zusätzlichen Metadaten belasten, aber meiner Erfahrung nach geben viele Dienste nicht alle Daten sofort zurück, sondern auf "paginierte" Weise.
Grizwako
105

Dein Beispiel ist gebrochen. Sie sollten keine JSON-Objekte mit doppelten Schlüsseln haben. Was Sie suchen, ist ein Array mit Filmobjekten, wie folgt :

 [
    {"name": "movie1"}, 
    {"name": "movie2"}
 ]

Dieser Ansatz beantwortet auch Ihre Frage. Sie sollten ein leeres Array zurückgeben, wenn die Abfrage nicht übereinstimmt:

[]

Wenn Sie andererseits versuchen, eine bestimmte Filmressource mit abzurufen, GET api/movie/34und dieser Film nicht vorhanden ist, geben Sie 404 mit einer geeigneten (json-codierten) Fehlermeldung im Hauptteil zurück

Martin Wickman
quelle
1
+1 Dies ist ein gültiger JSON gemäß json_xs.
10.
15

Wenn dies JSON ist, sollten Sie wirklich in Betracht ziehen, ein Array von Objekten zurückzugeben. Dies hat viele Vorteile, einschließlich der Tatsache, dass es sich bei keinem Datensatz um ein leeres Array handelt.

Wenn Sie also Aufzeichnungen haben, würden Sie zurückkehren:

    [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]

Und wenn Sie keine Aufzeichnungen haben, würden Sie zurückkehren:

    [

    ]
Devdatta Tengshe
quelle
14

Wenn Sie die Operation erfolgreich ausführen, aber nichts zurückzugeben hat, wie z. B. eine leere Karte {}oder ein leeres Array, []würde ich es vorziehen, mit dem Antwortcode 204 zu antworten. Hier ein Auszug aus den HTTP- Statuscode- Definitionen :

Der Server hat die Anforderung erfüllt, muss jedoch keinen Entity-Body zurückgeben und möchte möglicherweise aktualisierte Metainformationen zurückgeben. Die Antwort kann neue oder aktualisierte Metainformationen in Form von Entity-Headern enthalten, die, falls vorhanden, der angeforderten Variante zugeordnet werden MÜSSEN.

Wenn der Client ein Benutzeragent ist, DARF er die Dokumentansicht NICHT von der Ansicht ändern, die zum Senden der Anforderung geführt hat. Diese Antwort dient in erster Linie dazu, Eingaben für Aktionen zu ermöglichen, ohne die aktive Dokumentansicht des Benutzeragenten zu ändern, obwohl neue oder aktualisierte Metainformationen auf das Dokument angewendet werden MÜSSEN, das sich derzeit in der aktiven Ansicht des Benutzeragenten befindet.

Die Antwort 204 DARF KEINEN Nachrichtentext enthalten und wird daher immer durch die erste leere Zeile nach den Kopfzeilenfeldern abgeschlossen.

Grundsätzlich empfehle ich, 204 in RESTful-Anwendungen über HTTP zu verwenden, wenn nichts zurückzugeben ist.

David Sergey
quelle
4
Ich stimme @ avakars Kommentar zu einer anderen Antwort hier zu. Wenn der Client versucht, auf / v1 / get / movies / 1 zuzugreifen, sollte er 404 zurückgeben, wenn keine mit 1 identifizierbaren Filme vorhanden sind. Nur / v1 / get / movies sollte 200 zurückgeben, auch wenn kein Film vorhanden ist. Aber 204 ist nicht geeignet, weil es für Eingabeaktionen gedacht ist.
imel96
7
Ein weiteres Problem bei dieser Lösung besteht darin, dass in der Regel ein spezieller Code im Client erforderlich ist: Wenn die Antwort eine leere Liste ist, kann sie wie eine normale Antwort als JSON analysiert werden. Wenn die Antwort ein leerer Text ist, wird sich der JSON-Parser wahrscheinlich beschweren (da ein leeres Dokument kein gültiges JSON ist), sodass der Client zusätzlichen Code benötigt, um nach HTTP 204 zu suchen und das Parsen zu überspringen.
sleske
7
Ich glaube, dies ist eine Fehlinterpretation der Absicht von 204. 204 scheint nicht für Vorgänge gedacht zu sein, die Inhalt erwarteten und keinen fanden, sondern für Vorgänge, die erfolgreich waren und keine beabsichtigte Rückkehr haben . Aus Wikipedia: "Der Server hat die Anforderung erfolgreich verarbeitet, gibt jedoch keinen Inhalt zurück. Wird normalerweise als Antwort auf eine erfolgreiche Löschanforderung verwendet."
XML
10

An der Erstellung eines standardisierten JSON-API-Formats wurde ein angemessener Aufwand betrieben .

Gemäß den Grundsätzen in dieser Spezifikation sollten alle zurückgegebenen Ressourcen effektiv "Sammlungen" sein (auch wenn nur eine einzige Ressource enthalten ist). Wenn Sie dies befolgen, würde Ihr Anruf an folgende /v1/get/moviesAdresse zurückkehren:

{
    "movies": [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]
}

Ihr Anruf an /v1/get/books(der keine Ressourcen zurückgibt) würde Folgendes zurückgeben:

{
    "books": []
}
Tim Blair
quelle
5

Für Ihr spezielles Beispiel würde ich empfehlen, dass / v1 / get / books HTTP 200 mit einem leeren Array zurückgibt.

Wenn ich Ihren Beitrag richtig lese, beabsichtigt Ihre API, Bücher zu sammeln. Bildlich gesprochen haben Sie ein Bücherregal für Bücher, ein DVD-Regal für Filme und möglicherweise andere Behälter, die Sie hier nicht erwähnt haben. Weil Sie vorhaben, Bücher zu sammeln, ist / v1 / get / books Ihr Bücherregal. Dies bedeutet, dass es dort eine gültige Ressource gibt - eine Liste von Büchern -, die in Ihrem speziellen Beispiel leer ist.

Der Grund, warum ich nicht vorschlage, HTTP 404 in diesem Fall zurückzugeben, ist, dass das Bücherregal noch vorhanden ist. Momentan gibt es keine Bücher darüber, aber es ist immer noch ein Bücherregal. Wenn es nicht ein Bücherregal -wenn die API nicht zu sammeln Bücher die Absicht hatte, für Beispiel- dann HTTP 404 angebracht wäre. Aber weil es dort eine Ressource gibt, sollten Sie nicht signalisieren, dass es keine gibt, was HTTP 404 tut. Daher argumentiere ich, dass 200 mit einem leeren Array (das die Auflistung kennzeichnet) angemessener ist.

Der Grund, warum ich nicht vorschlage, HTTP 204 zurückzugeben, ist, dass dies darauf hindeutet, dass "Kein Inhalt" der normale Zustand ist: Wenn Sie diese Aktion für diese Ressource ausführen, wird normalerweise nichts zurückgegeben. Aus diesem Grund wird es normalerweise als Antwort auf DELETE-Anforderungen verwendet, z. B. bedeutet die Art des Löschens im Allgemeinen, dass nichts zurückgegeben werden muss. Ähnlich verhält es sich bei der Beantwortung von Anfragen mit der If-Modified-Familie von Headern: Sie wollten nur Inhalte, wenn sich die Ressource geändert hat, aber nicht. Deshalb werde ich Ihnen keine Inhalte geben.

Ich behaupte jedoch, dass HTTP 204 für das Abrufen einer leeren, aber gültigen Auflistung keinen Sinn ergibt. Wenn sich Elemente in der Auflistung befänden, wäre die richtige Darstellung ein Array dieser Daten. Wenn dort keine Daten vorhanden sind (aber die Auflistung gültig ist), ist die richtige Darstellung daher ein leeres Array.

Der Löffeligste
quelle
5

Sie sollten wirklich nur eines von zwei Dingen tun

Entweder Sie geben einen 200 (OK)Statuscode und ein leeres Array im Hauptteil zurück.

Oder 204 (NO CONTENT)Statuscode und KEIN Antworttext zurückgeben.

Option 2 erscheint mir technisch korrekter und entspricht den Grundsätzen von REST und HTTP.

Option 1 scheint jedoch für den Client effizienter zu sein, da der Client keine zusätzliche Logik benötigt, um zwischen zwei (Erfolgs-) Statuscodes zu unterscheiden. Da es weiß, dass es immer ein Array empfängt, muss es nur prüfen, ob es keines, eines oder viele Elemente enthält, und es muss entsprechend verarbeitet werden

Vihung
quelle
3

Ich habe beide Fälle in Produktionsumgebungen gesehen. Welche Sie auswählen, hängt davon ab, wer die API verwenden wird. Wenn sie wissen möchten, warum die Liste leer ist oder ob die Liste wirklich leer ist und beim Abrufen keine Fehler aufgetreten sind, sollten Sie ein "Fehler" -Objekt anhängen. Wenn es ihnen egal ist, schicken Sie eine leere Liste zurück. Ich würde den zweiten Ansatz wählen, da er mehr Bedürfnisse als der erste abdeckt.

devnull
quelle
3

Da Sie eine RESTful-API erstellen, müssen Sie zunächst einen geeigneten Antwortcode zurückgeben. Und der passendere Antwortcode, um mitzuteilen, dass die Anforderung normal durchlaufen wurde, die angeforderte Ressource jedoch momentan nicht verfügbar ist, ist der ehrwürdige 404.

Wenn Sie Ihre API so gestalten, dass sie immer einen vernünftigen Antwortcode zurückgibt, müssen Sie möglicherweise nicht einmal einen Text zurückgeben, wenn die Ressource nicht gefunden wurde. Das heißt, die Rückgabe eines Körpers, insbesondere eines von Menschen lesbaren, kann nicht schaden.

Hier gibt es keine "Best Practice", beide Beispiele sind willkürlich, wählen Sie einfach eines aus und seien Sie konsequent . Entwickler hassen Überraschungen, wenn sie /v1/get/movieszurückkehren, {}wenn es keine Filme gibt, dann würden wir erwarten /v1/get/actors, dass sie auch zurückkehren, {}wenn es keine Schauspieler gibt.

yannis
quelle
1
Ein 404 zurückzugeben ist wirklich das Richtige, aber leider tut es niemand wirklich - ich selbst eingeschlossen.
RibaldEddie
1
Wenn Sie komplexe Antworten haben und nur Teile davon leer sind, verwirrt das Zurückgeben eines 404 den Benutzer.
Devnull
5
Ich würde mit der 404-Nachricht nicht einverstanden sein. Ein 404 würde ich als "Ressource existiert nicht" interpretieren und mir Sorgen machen, wenn mit meiner URL oder was auch immer etwas nicht stimmt. Wenn ich nach einer Liste von Filmen frage und eine 404 bekomme, würde ich denken, dass es überhaupt keine Filmressource gibt. Ein "204 No Content" kann angemessener sein.
thorsten müller
8
Ok, das "no body" Ding würde es töten. Aber: "Die Statuscode-Klasse 4xx ist für Fälle vorgesehen, in denen der Client einen Fehler zu haben scheint." Auf der Clientseite gab es jedoch keinen Fehler. Ein 404 gibt also falsche Informationen. Senden Sie entweder 204 ohne Text oder sagen Sie, dass es in Ordnung ist, und senden Sie eine leere Liste.
thorsten müller
9
Wenn Sie nach einer Bücherliste fragen und 404 zurückgeben, bedeutet dies, dass die Liste nicht existiert und nicht leer ist. Die Rückgabe von 200 zusammen mit einer leeren Liste scheint mir die einzig sinnvolle Option zu sein.
Avakar
1

Ich glaube nicht, dass die richtige Antwort die markierte ist.

Die Antwort von nirth sollte in einem echten REST-Szenario die beste sein. Die Body-Antwort sollte leer sein und der http-Statuscode: 204; Die Ressource existiert, hat aber zu diesem Zeitpunkt "keinen Inhalt": ist leer.

REST HTTP_Status_Codes

jmmtcarvalho
quelle
1

Ich empfehle 200 + leeres Array, da es die Handhabung für alle Clients der API vereinfacht. 200 + Array bedeutet "Ich habe alle Daten zurückgegeben, die dort sind". Sowohl für den Code, der die Daten liefert, als auch für den Code, der sie verarbeitet, wäre die Anzahl der Elemente irrelevant.

Jeder andere Statuscode muss ordnungsgemäß dokumentiert und vom Server ordnungsgemäß übermittelt und vom Client ordnungsgemäß verarbeitet werden. Wir alle wissen, wie wahrscheinlich dies ist.

Es wurde vorgeschlagen, den Status 204 + leerer Körper zurückzugeben. Das heißt, Sie erzwingen, dass jeder einzelne Client den Status 204 korrekt verarbeitet. Außerdem zwingen Sie sie, Nicht-JSON-Antworten zu verarbeiten! Ich hoffe, jeder merkt, dass eine Anfrage, die eine Antwort erhalten hat, nicht bedeutet, dass die Antwort vom Server stammt, wenn http verwendet wird, und nur überprüft, ob die Antwort JSON ist, um viele dieser Fälle zu behandeln.

gnasher729
quelle
0

Ich würde "Es kommt darauf an".

Wenn Null ein vernünftiges Ergebnis ist, geben Sie die leere Liste zurück. Zum Beispiel, wenn Sie alle Mitarbeiter mit dem Namen "bob" beauftragen möchten, wobei "none" ein vernünftiges Ergebnis ist. Wenn es sich nicht um ein erwartetes Ergebnis handelt, wird ein Fehler zurückgegeben. Zum Beispiel eine historische Liste von Straßenadressen für eine Person, die Sie beschäftigen. Sie müssen irgendwo leben, damit kein Ergebnis wahrscheinlich ein Fehler ist, nicht nur ein normaler Zustand.

Ich bin sicher, Sie können mit den Einzelheiten meines Beispiels streiten, aber Sie haben die Idee ...

JohnB
quelle
0
  • Erstens getist GET in Ihrer URL nicht REST-konform und wird von der HTTP-Methode impliziert.
  • Wenn Sie eine Sammlung wie GET api/moviesa anfordern, geben Sie a 200 OKmit einem leeren Array zurück [].
  • Wenn Sie einen bestimmten Film wie GET api/movies/1(wo 1ist die ID) anfordern und dieser nicht vorhanden ist, geben Sie a zurück 404 Not Found.

Warum? Sie fordern Ressourcen an . Wenn Sie die Sammlung anfordern, ist die Ressource selbst (die Sammlung) vorhanden. Daher ist a 404falsch. Wenn Sie jedoch einen bestimmten Film anfordern und dieser nicht vorhanden ist, ist die angeforderte Ressource nicht vorhanden, und Sie müssen a zurückgeben 404.

felixfbecker
quelle
-2

Wenn Sie JSON zurückgeben, ist es besser, immer count und error message und möglicherweise einen Boolean zurückzugeben, der angibt, ob ein Fehler vorliegt oder nicht. Dies sind meine drei Standard-Metawerte, die mit jeder Zeilenliste zurückgegeben werden.

Sino
quelle