webentwicklung-frage-antwort-db.com.de

Was ist die beste RESTful-Methode, um die Gesamtzahl der Elemente in einem Objekt zurückzugeben?

Ich entwickle einen REST API-Service für eine große Social-Networking-Website, an der ich beteiligt bin. Bisher funktioniert er hervorragend. Ich kann GET, POST, PUT und DELETE fordern Objekt-URLs an und wirken sich auf meine Daten aus. Diese Daten werden jedoch paginiert (jeweils auf 30 Ergebnisse begrenzt).

Was wäre jedoch der beste REST-Weg, um die Gesamtzahl der Mitwirkenden über meine API zu ermitteln?

Derzeit stelle ich Anfragen an eine URL-Struktur wie die folgende:

  • / api/members - Gibt eine Liste von Mitgliedern zurück (jeweils 30 wie oben erwähnt)
  • / api/members/1 - Betrifft ein einzelnes Mitglied, abhängig von der verwendeten Anforderungsmethode

Meine Frage ist: Wie würde ich dann eine ähnliche URL-Struktur verwenden, um die Gesamtzahl der Mitglieder in meiner Bewerbung zu ermitteln? Offensichtlich wäre es ineffektiv, nur das id -Feld anzufordern (ähnlich wie bei der Grafik-API von Facebook) und die Ergebnisse zu zählen, da nur ein Teil von 30 Ergebnissen zurückgegeben würde.

123
Martin Bean

Während die Antwort an/API/users ausgelagert wird und nur 30 Datensätze zurückgibt, hindert nichts Sie daran, die Gesamtzahl der Datensätze und andere relevante Informationen wie die Seitengröße, die Seitenzahl/den Versatz usw. In die Antwort einzubeziehen .

Die StackOverflow-API ist ein gutes Beispiel für dasselbe Design. Hier ist die Dokumentation für die Users-Methode - https://api.stackexchange.com/docs/users

78
Franci Penov

Ich bevorzuge die Verwendung von HTTP-Headern für diese Art von Kontextinformationen.

Für die Gesamtzahl der Elemente verwende ich X-total-count Header.
Für Links zur nächsten, vorherigen Seite usw. verwende ich den http Link -Header:
http://www.w3.org/wiki/LinkHeader

Github macht es genauso: https://developer.github.com/v3/#pagination

Meiner Meinung nach ist es sauberer, da es auch verwendet werden kann, wenn Sie Inhalte zurückgeben, die keine Hyperlinks unterstützen (z. B. Binärdateien, Bilder).

62
Ondrej Bozek

Ich habe mich in letzter Zeit eingehend mit diesen und anderen Fragen im Zusammenhang mit REST Paging befasst und es für konstruktiv befunden, hier einige meiner Ergebnisse einzufügen. Ich erweitere die Frage ein wenig, um sowohl die Paging-Gedanken als auch die Anzahl zu berücksichtigen, da sie eng miteinander verbunden sind.

Überschriften

Die Paging-Metadaten sind in der Antwort in Form von Antwortköpfen enthalten. Der große Vorteil dieses Ansatzes besteht darin, dass die Antwortnutzlast selbst nur die tatsächliche Datenanforderung ist, nach der der Benutzer gefragt hat. Erleichterung der Verarbeitung der Antwort für Clients, die nicht an den Paging-Informationen interessiert sind.

Es gibt eine Reihe von (Standard- und benutzerdefinierten) Headern, die in freier Wildbahn verwendet werden, um pagingbezogene Informationen zurückzugeben, einschließlich der Gesamtanzahl.

X-Total-Count

X-Total-Count: 234

Dies wird in einigenAPIs verwendet, die ich in freier Wildbahn gefunden habe. Es gibt auch NPM-Pakete , um Unterstützung für diesen Header z.B. Loopback. Einige Artikel empfehlen, auch diesen Header zu setzen.

Es wird häufig in Kombination mit dem Header Link verwendet. Dies ist eine gute Lösung für das Blättern, es fehlen jedoch die Informationen zur Gesamtanzahl.

Verknüpfung

Link: </TheBook/chapter2>;
      rel="previous"; title*=UTF-8'de'letztes%20Kapitel,
      </TheBook/chapter4>;
      rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel

Ich bin der Meinung, dass es nach vielem Lesen zu diesem Thema allgemein üblich ist, den Link -Header zu verwenden, um Paging-Links für Clients mit rel=next, rel=previous Usw. Das Problem dabei ist, dass es keine Informationen darüber gibt, wie viele Datensätze insgesamt vorhanden sind, weshalb viele APIs dies mit dem Header X-Total-Count Kombinieren.

Alternativ können einige APIs und z.B. Verwenden Sie im JsonApi -Standard das Link -Format, fügen Sie jedoch die Informationen in einem Antwortumschlag anstelle eines Headers hinzu. Dies vereinfacht den Zugriff auf die Metadaten (und schafft einen Platz zum Hinzufügen der Gesamtzahlinformationen) auf Kosten der zunehmenden Komplexität des Zugriffs auf die eigentlichen Daten (durch Hinzufügen eines Umschlags).

Inhaltsbereich

Content-Range: items 0-49/234

Gefördert durch einen Blog-Artikel namens Range-Header, ich wähle Sie (für die Paginierung)! . Der Autor spricht sich stark dafür aus, die Überschriften Range und Content-Range Für die Paginierung zu verwenden. Wenn wir the RFC auf diesen Headern sorgfältig lesen, stellen wir fest, dass das Erweitern ihrer Bedeutung über Bytebereiche hinaus tatsächlich vom RFC erwartet wurde und ist ausdrücklich erlaubt. Wenn der Range-Header im Kontext von items anstelle von bytes verwendet wird, haben wir die Möglichkeit, einen bestimmten Bereich von Elementen anzufordern und anzugeben, auf welchen Bereich des Gesamtergebnisses sich die Antwortelemente beziehen . Diese Kopfzeile bietet auch eine gute Möglichkeit, die Gesamtzahl anzuzeigen. Und es ist ein wahrer Standard, der Paging meistens eins zu eins zuordnet. Es ist auch in freier Wildbahn verwendet .

Briefumschlag

Viele APIs, einschließlich die von unserer bevorzugten Q & A-Website verwenden einen Umschlag , einen Wrapper um die Daten, die zum Hinzufügen verwendet werden Meta-Informationen zu den Daten. Außerdem verwenden die Standards OData und JsonApi beide einen Antwortumschlag.

Der große Nachteil dabei (imho) ist, dass die Verarbeitung der Antwortdaten komplexer wird, da die tatsächlichen Daten irgendwo im Umschlag gefunden werden müssen. Es gibt auch viele verschiedene Formate für diesen Umschlag und Sie müssen das richtige verwenden. Es ist aufschlussreich, dass die Antwortumschläge von OData und JsonApi sehr unterschiedlich sind, da OData Metadaten an mehreren Stellen in der Antwort mischen.

Separater Endpunkt

Ich denke, das wurde in den anderen Antworten ausreichend behandelt. Ich habe nicht so viel untersucht, weil ich den Kommentaren zustimme, dass dies verwirrend ist, da Sie jetzt mehrere Arten von Endpunkten haben. Ich finde es am schönsten, wenn jeder Endpunkt eine (Sammlung von) Ressource (n) darstellt.

Weitere Gedanken

Wir müssen nicht nur die Paging-Metainformationen in Bezug auf die Antwort kommunizieren, sondern dem Client auch ermöglichen, bestimmte Seiten/Bereiche anzufordern. Es ist interessant, auch diesen Aspekt zu betrachten, um eine kohärente Lösung zu erhalten. Auch hier können wir Header (der Header Range scheint sehr gut geeignet zu sein) oder andere Mechanismen wie Abfrageparameter verwenden. Einige befürworten, Ergebnisseiten als separate Ressourcen zu behandeln, was in einigen Anwendungsfällen sinnvoll sein kann (z. B. /books/231/pages/52). Am Ende habe ich eine Reihe häufig verwendeter Anforderungsparameter ausgewählt, z. B. pagesize, page[size] Und limit etc zusätzlich zur Unterstützung des Headers Range (und auch als Anforderungsparameter).

56
Stijn de Witt

Sie können die Anzahl als benutzerdefinierten HTTP-Header als Antwort auf eine HEAD) - Anforderung zurückgeben. Auf diese Weise müssen Sie die aktuelle Liste nicht zurückgeben, wenn ein Client nur die Anzahl möchte Keine zusätzliche URL erforderlich.

(Wenn Sie sich in einer kontrollierten Umgebung von Endpunkt zu Endpunkt befinden, können Sie ein benutzerdefiniertes HTTP-Verb wie COUNT verwenden.)

22
bzlm

Alternative, wenn Sie keine aktuellen Artikel benötigen

Franci Penovs Antwort ist sicherlich der beste Weg, damit Sie immer Artikel mit allen zusätzlichen Metadaten zu Ihren angeforderten Entitäten zurückgeben. So sollte es gemacht werden.

manchmal ist es jedoch nicht sinnvoll, alle Daten zurückzugeben, da Sie sie möglicherweise gar nicht benötigen. Möglicherweise benötigen Sie nur diese Metadaten zu Ihrer angeforderten Ressource. Wie Gesamtzahl oder Anzahl der Seiten oder etwas anderes. In diesem Fall können Sie jederzeit eine URL-Abfrage veranlassen, Ihrem Service mitzuteilen, dass keine Artikel zurückgegeben werden sollen, sondern nur Metadaten wie:

/api/members?metaonly=true
/api/members?includeitems=0

oder etwas ähnliches...

21
Robert Koritnik

Ich würde empfehlen, Header für das gleiche hinzuzufügen, wie:

HTTP/1.1 200

Pagination-Count: 100
Pagination-Page: 5
Pagination-Limit: 20
Content-Type: application/json

[
  {
    "id": 10,
    "name": "shirt",
    "color": "red",
    "price": "$23"
  },
  {
    "id": 11,
    "name": "shirt",
    "color": "blue",
    "price": "$25"
  }
]

Einzelheiten finden Sie unter:

https://github.com/adnan-kamili/rest-api-response-format

Für Swagger-Datei:

https://github.com/adnan-kamili/swagger-response-template

11
adnan kamili

Ab "X -" - Präfix veraltet. (siehe: https://tools.ietf.org/html/rfc6648 )

Wir haben festgestellt, dass die "Accept-Ranges" die beste Wahl sind, um den Paginierungsbereich abzubilden: https://tools.ietf.org/html/rfc7233#section-2. Wie die "Range Units" entweder "bytes" oder "token". Beide repräsentieren keinen benutzerdefinierten Datentyp. (siehe: https://tools.ietf.org/html/rfc7233#section-4.2 ) Trotzdem heißt es, dass

HTTP/1.1-Implementierungen KÖNNEN Bereiche ignorieren, die mit anderen Einheiten angegeben wurden.

Was bedeutet: Die Verwendung von benutzerdefinierten Bereichseinheiten ist nicht gegen das Protokoll, kann jedoch ignoriert werden.

Auf diese Weise müssten wir die Akzeptanzbereiche auf "Mitglieder" oder den erwarteten Einheitentyp festlegen. Stellen Sie außerdem den Inhaltsbereich auf den aktuellen Bereich ein. (siehe: https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.12 )

In jedem Fall würde ich mich an die Empfehlung von RFC7233 ( https://tools.ietf.org/html/rfc7233#page-8 ) halten, eine 206 anstelle von 200 zu senden:

Wenn alle Voraussetzungen erfüllt sind, unterstützt der Server den Bereich
Header-Feld für die Zielressource und die angegebenen Bereiche sind
gültig und zufriedenstellend (wie in Abschnitt 2.1 definiert), SOLLTE der Server
sendet eine 206-Antwort (Teilinhalt) mit einer Nutzlast, die eine enthält
oder mehr Teildarstellungen, die dem Erfüllbaren entsprechen
angeforderte Bereiche gemäß Definition in Abschnitt 4.

Als Ergebnis hätten wir also die folgenden HTTP-Header-Felder:

Für Teilinhalte:

206 Partial Content
Accept-Ranges: members
Content-Range: members 0-20/100

Für den vollständigen Inhalt:

200 OK
Accept-Ranges: members
Content-Range: members 0-20/20
5
Lepidopteron

Was ist mit einem neuen Endpunkt>/api/members/count, der nur Members.Count () aufruft und das Ergebnis zurückgibt?

2
Steve Woods

Scheint am einfachsten, einfach eine hinzuzufügen

GET
/api/members/count

und geben die Gesamtzahl der Mitglieder zurück

2

Manchmal erfordern Frameworks (wie $ resource/AngularJS) ein Array als Abfrageergebnis, und Sie können nicht wirklich eine Antwort wie {count:10,items:[...]} In diesem Fall speichere ich "count" in responseHeaders.

P. S. Eigentlich kannst du das mit $ resource/AngularJS machen, aber es braucht ein paar Verbesserungen.

2