Paging in einer Rest-Sammlung

134

Ich bin daran interessiert, eine direkte REST-Schnittstelle für Sammlungen von JSON-Dokumenten bereitzustellen (denken Sie an CouchDB oder Persevere ). Das Problem, auf das ich stoße, ist, wie der GETVorgang im Sammlungsstamm behandelt wird, wenn die Sammlung groß ist.

Stellen Sie sich als Beispiel vor, ich mache die QuestionsTabelle von StackOverflow verfügbar, in der jede Zeile als Dokument verfügbar gemacht wird (nicht, dass es unbedingt eine solche Tabelle gibt, sondern nur ein konkretes Beispiel für eine umfangreiche Sammlung von 'Dokumenten'). Die Sammlung würde zur Verfügung gestellt wird /db/questionsmit dem üblichen CRUD api GET /db/questions/XXX, PUT /db/questions/XXX, POST /db/questionsist im Spiel. Der Standardweg, um die gesamte Sammlung GET /db/questionsabzurufen, besteht darin, aber wenn dadurch jede Zeile naiv als JSON-Objekt ausgegeben wird, erhalten Sie einen ziemlich umfangreichen Download und viel Arbeit seitens des Servers.

Die Lösung ist natürlich Paging. Dojo hat dieses Problem in seinem JsonRestStore über eine clevere RFC2616-kompatible Erweiterung der Verwendung des RangeHeaders mit einer benutzerdefinierten Bereichseinheit gelöst items. Das Ergebnis ist ein 206 Partial Content, das nur den angeforderten Bereich zurückgibt. Der Vorteil dieses Ansatzes gegenüber einem Abfrageparameter besteht darin, dass die GET /db/questions/?score>200Abfragezeichenfolge für ... Abfragen verbleibt (z. B. oder so, und ja, das würde codiert %3E).

Dieser Ansatz deckt das gewünschte Verhalten vollständig ab. Das Problem ist, dass RFC 2616 dies bei einer 206-Antwort angibt (Hervorhebung von mir):

Die Anforderung MUSS ein Bereichs-Header-Feld ( Abschnitt 14.35 ) enthalten, das den gewünschten Bereich angibt, und KANN ein If-Range-Header-Feld ( Abschnitt 14.27 ) enthalten, um die Anforderung bedingt zu machen.

Dies ist im Zusammenhang mit der Standardverwendung des Headers sinnvoll, stellt jedoch ein Problem dar, da ich möchte, dass die Antwort 206 die Standardeinstellung für naive Clients / zufällige Personen ist.

Ich habe den RFC im Detail durchgesehen und nach einer Lösung gesucht, war aber mit meinen Lösungen unzufrieden und bin daran interessiert, dass SO das Problem aufgreift.

Ideen, die ich hatte:

  • Kehre 200mit einem Content-RangeHeader zurück! - Ich denke nicht, dass dies falsch ist, aber ich würde es vorziehen, wenn ein offensichtlicherer Indikator dafür ist, dass die Antwort nur Teilinhalt ist.
  • Rückgabe400 Range Required - Es gibt keinen speziellen 400-Antwortcode für die erforderlichen Header, daher muss der Standardfehler von Hand verwendet und gelesen werden. Dies erschwert auch die Erkundung über einen Webbrowser (oder einen anderen Client wie Resty).
  • Verwenden Sie einen Abfrageparameter - Der Standardansatz, aber ich hoffe, Abfragen a la Persevere zuzulassen, und dies schneidet in den Abfrage-Namespace.
  • Komm einfach zurück 206! - Ich denke, die meisten Kunden würden nicht ausflippen, aber ich würde lieber nicht gegen ein MUSS im RFC vorgehen
  • Erweitern Sie die Spezifikation! Return266 Partial Content - Verhält sich genau wie 206, ist jedoch eine Antwort auf eine Anfrage, die den RangeHeader NICHT enthalten darf. Ich denke, dass 266 hoch genug ist, um nicht auf Kollisionsprobleme zu stoßen, und es macht für mich Sinn, aber ich bin mir nicht sicher, ob dies als tabu angesehen wird oder nicht.

Ich würde denken, dass dies ein ziemlich häufiges Problem ist und ich würde es gerne de facto sehen, damit ich oder jemand anderes das Rad nicht neu erfinden.

Was ist der beste Weg, um eine vollständige Sammlung über HTTP verfügbar zu machen, wenn die Sammlung groß ist?

Karl Guertin
quelle
21
Wow, das ist ein gutes Beispiel für eine Frage, bei der schon einmal ernsthaft nachgedacht wurde.
Heiko Rupp
Mögliches Duplikat der Paginierung in einer REST-Webanwendung
25.
1
Was Dojos Ansatz bei der Verwendung des Range-Headers angeht , obwohl Accept-Ranges eine Erweiterung zulässt, tut der EBNF für Range nach allem, was ich sagen kann, nicht: tools.ietf.org/html/rfc2616#section-14.35.2 . Die Spezifikation gibt an, Range = "Range" ":" ranges-specifierwo letztere in tools.ietf.org/html/rfc2616#section-14.35.1 lediglich als " Bytebereichs -Spezifizierer" beschrieben wird, der mit "Byte-Einheit" beginnen muss, die als Zeichenfolge "Bytes" definiert ist ".
Brett Zamir
2
Der Content-RangeHeader gilt für den Body (kann mit Anfrage beim Hochladen großer Dateien usw. oder als Antwort beim Herunterladen verwendet werden). Der RangeHeader wird verwendet, um einen bestimmten Bereich anzufordern. Man sollte antworten, 206wann der RangeHeader in der Anfrage enthalten war. Wenn dies nicht der Content-RangeFall ist , enthält die Antwort möglicherweise noch einen Header, der Antwortcode sollte jedoch lauten 200. Dieser Header scheint eigentlich ideal zum Blättern zu sein.
Stijn de Witt
Der RFC 2616 selbst sagt jedoch, dass "HTTP / 1.1-Implementierungen Bereiche ignorieren können, die mit anderen Einheiten angegeben wurden." Ist es also eine gute Praxis, Range-Header für die Paginierung zu verwenden? Weil es die Interoperabilität beeinträchtigen könnte.
Chetan Choulwar

Antworten:

23

Mein Bauchgefühl ist, dass die HTTP-Bereichserweiterungen nicht für Ihren Anwendungsfall entwickelt wurden und Sie es daher nicht versuchen sollten. Eine teilweise Antwort impliziert 206und 206muss nur gesendet werden, wenn der Client danach gefragt hat.

Möglicherweise möchten Sie einen anderen Ansatz in Betracht ziehen, z. B. den in Atom verwendeten (bei dem die Darstellung aufgrund des Entwurfs teilweise sein kann und mit einem Status 200und möglicherweise Paging-Links zurückgegeben wird). Siehe RFC 4287 und RFC 5005 .

Julian Reschke
quelle
14
Die Dojo-Nutzung entspricht vollständig den Spezifikationen. Wenn der Server die itemsBereichseinheit nicht versteht , gibt er eine vollständige Antwort zurück. Ich bin mit Atom vertraut, aber das ist nicht die allgemeine Lösung für Rest Paging. Dies ist keine Lösung für einen Einzelfall, sondern eher die allgemeine Lösung. Nicht alle Dokumente / Sammlungen passen zum Atom-Modell, und es gibt keinen Grund, es zu erzwingen, es sei denn, dies ist erforderlich.
Karl Guertin
1
@ KarlGuertin Einverstanden. Schade, dass dies die akzeptierte Antwort ist, denn es scheint, dass viele in der Community sich tatsächlich umarmen Rangeund Content-Rangezu Paging-Zwecken.
Stijn de Witt
34

Ich stimme einigen von euch nicht wirklich zu. Ich arbeite seit Wochen an diesen Funktionen für meinen REST-Service. Was ich letztendlich gemacht habe, ist wirklich einfach. Meine Lösung macht nur Sinn für das, was REST-Leute eine Sammlung nennen.

Der Client MUSS einen "Range" -Header einfügen, um anzugeben, welchen Teil der Sammlung er benötigt, oder auf andere Weise bereit sein, einen 413 REQUESTED ENTITY TOO LARGE-Fehler zu behandeln, wenn die angeforderte Sammlung zu groß ist, um in einem einzigen Roundtrip abgerufen zu werden.

Der Server sendet eine 206 PARTIAL CONTENT-Antwort, wobei der Content-Range-Header angibt, welcher Teil der Ressource gesendet wurde, und ein ETag-Header, um die aktuelle Version der Sammlung zu identifizieren. Normalerweise verwende ich ein Facebook-ähnliches ETag {last_modification_timestamp} - {resource_id} und bin der Meinung, dass das ETag einer Sammlung das der zuletzt geänderten Ressource ist, die es enthält.

Um einen bestimmten Teil einer Sammlung anzufordern, MUSS der Client den Header "Range" verwenden und den Header "If-Match" mit dem ETag der Sammlung füllen, das aus zuvor durchgeführten Anforderungen zum Erwerb anderer Teile derselben Sammlung erhalten wurde. Der Server kann daher überprüfen, ob sich die Sammlung nicht geändert hat, bevor der angeforderte Teil gesendet wird. Wenn eine neuere Version vorhanden ist, wird eine Antwort 412 PRECONDITION FAILED zurückgegeben, um den Client aufzufordern, die Sammlung von Grund auf neu abzurufen. Dies ist erforderlich, da dies bedeuten kann, dass einige Ressourcen vor oder nach dem aktuell angeforderten Teil hinzugefügt oder entfernt wurden.

Ich verwende ETag / If-Match zusammen mit Last-Modified / If-Unmodified-Since, um den Cache zu optimieren. Browser und Proxys verlassen sich möglicherweise auf einen oder beide von ihnen für ihre Caching-Algorithmen.

Ich denke, dass eine URL sauber sein sollte, es sei denn, sie soll eine Such- / Filterabfrage enthalten. Wenn Sie darüber nachdenken, ist eine Suche nichts anderes als eine Teilansicht einer Sammlung. Anstelle der Autos / Suche? Q = BMW Typ von URLs sollten wir mehr Autos sehen? Hersteller = BMW.

Mohamed
quelle
Meinten Sie 416 "Angeforderter Bereich nicht zufriedenstellend" oder "413" Anforderungsentität zu groß?
1
@Mohamed Ich denke du meinst If-Unmodified-Since, was If-Matcheher der E-Tag Variante entspricht als If-Modified-Since. Abhängig von Ihrem Anwendungsfall können Sie diese Einschränkung jedoch auch entfernen. Angenommen, Sie haben eine Sammlung, die nur von oben wächst (wie eine Sammlung im "neuesten ersten" Stil). Das Schlimmste, was passieren kann, wenn sich diese Sammlung zwischen Anforderungen ändert, ist, dass ein Benutzer, der eine Sammlung durchblättert, Einträge zweimal sieht. (Was an sich auch eine nützliche Information ist: Es teilt dem Benutzer mit, dass sich die Sammlung geändert hat)
Eugene Beresovsky
20
413 ist "Anforderungsentität zu groß anfordern", nicht "Angeforderte Entität zu groß". Dies bedeutet, dass die Größe Ihrer Anfrage, beispielsweise beim Hochladen einer Datei, größer ist, als der Server verarbeiten möchte. Daher scheint es nicht völlig angemessen zu sein, es dafür zu verwenden.
user247702
@Mohamed Ich weiß, dass es eine alte Frage ist, aber wenn das ETag einer Sammlung das ETag der zuletzt geänderten Ressource ist, die die Sammlung enthält, welcher Wert des If-Match-Headers sollte beim Ändern einer Ressource in der Sammlung verwendet werden? Die Verwendung des mit der Auflistung zurückgegebenen ETag-Werts ist falsch, da der Client die Ressource ändern kann, auch wenn er den letzten Status der Ressource nicht sieht.
Mickael Marrache
8
Ich bin völlig anderer Meinung über die Verwendung 413. Dies ist ein Fehlercode, der bedeutet, dass der Client etwas sendet , das der Server aufgrund seiner Größe nicht akzeptiert. Nicht umgekehrt! Siehe tools.ietf.org/html/rfc7231#section-6.5.11 (beachten Sie, dass dort Anforderungsnutzlast steht . Nicht Antwortnutzlast )!
Exhuma
7

Sie können immer noch zurückkehren Accept-Rangesund Content-Rangesmit einem 200Antwortcode. Diese beiden Antwortheader geben Ihnen genügend Informationen, um auf dieselben Informationen zu schließen, die ein 206Antwortcode explizit bereitstellt.

Ich würde es Rangefür die Paginierung verwenden und es einfach 200für eine Ebene zurückgeben lassen GET.

Dies fühlt sich zu 100% RESTful an und erschwert das Surfen nicht.

Bearbeiten: Ich habe einen Blog-Beitrag dazu geschrieben: http://otac0n.com/blog/2012/11/21/range-header-i-choose-you.html

John Gietzen
quelle
5

Wenn es mehr als eine Seite mit Antworten gibt und Sie nicht die gesamte Sammlung auf einmal anbieten möchten, bedeutet dies, dass es mehrere Möglichkeiten gibt?

Bei einer Anfrage an /db/questionskehren Sie 300 Multiple Choicesmit LinkÜberschriften zurück, die angeben, wie zu jeder Seite gelangt werden soll, sowie mit einem JSON-Objekt oder einer HTML-Seite mit einer Liste von URLs.

Link: <>; rel="http://paged.collection.example/relation/paged"
Link: <>; rel="http://paged.collection.example/relation/paged"
...

Sie hätten einen LinkHeader für jede Ergebnisseite (eine leere Zeichenfolge bedeutet die aktuelle URL, und die URL ist für jede Seite gleich, auf die nur mit unterschiedlichen Bereichen zugegriffen wird), und die Beziehung wird gemäß der kommenden LinkSpezifikation als benutzerdefinierte definiert . Diese Beziehung würde Ihren Brauch 266oder Ihre Verletzung von erklären 206. Diese Header sind Ihre maschinenlesbare Version, da alle Ihre Beispiele ohnehin einen verständnisvollen Client erfordern.

(Wenn Sie sich an die "Range" -Route halten, ist Ihr eigener 2xxRückkehrcode, wie Sie ihn beschrieben haben , meiner Meinung nach das beste Verhalten. Von Ihnen wird erwartet, dass Sie dies für Ihre Anwendungen tun, und solche ["HTTP-Statuscodes sind erweiterbar. "] und du hast gute Gründe.)

300 Multiple Choicessagt, Sie sollten einem Körper auch eine Möglichkeit bieten, die der Benutzeragent auswählen kann. Wenn Ihr Client versteht, sollte er die LinkHeader verwenden. Wenn ein Benutzer manuell surft, möglicherweise eine HTML-Seite mit Links zu einer speziellen "ausgelagerten" Stammressource, die das Rendern dieser bestimmten Seite basierend auf der URL handhaben kann? /humanpage/1/db/questionsoder so etwas abscheuliches?


Die Kommentare zu Richard Levasseurs Beitrag erinnern mich an eine zusätzliche Option: den AcceptHeader (Abschnitt 14.1). Als die oEmbed-Spezifikation herauskam, fragte ich mich, warum sie nicht vollständig über HTTP erstellt worden war, und schrieb eine Alternative mit ihnen.

Behalten Sie die 300 Multiple Choices, die LinkHeader und die HTML-Seite für ein anfängliches naives HTTP bei GET, aber anstatt Bereiche zu verwenden, lassen Sie Ihre neue Paging-Beziehung die Verwendung des AcceptHeaders definieren. Ihre nachfolgende HTTP-Anfrage könnte folgendermaßen aussehen:

GET /db/questions HTTP/1.1
Host: paged.collection.example
Accept: application/json;PagingSpec=1.0;page=1

In der AcceptKopfzeile können Sie einen akzeptablen Inhaltstyp (Ihre JSON-Rückgabe) sowie erweiterbare Parameter für diesen Typ (Ihre Seitenzahl) definieren. Wenn Sie meine Notizen aus meinem oEmbed-Artikel lesen (kann hier nicht verlinkt werden, ich werde sie in meinem Profil auflisten), können Sie sehr explizit sein und hier eine Spezifikations- / Beziehungsversion angeben, falls Sie neu definieren müssen, was der pageParameter bedeutet in der Zukunft.

Vitorio
quelle
1
+1 Link-Header, aber ich würde auch die allgemeinen rels first, prev, next, last sowie das prev-archive, next-archive und current von RFC5005 empfehlen.
Joseph Holsten
> Geben Sie bei einer Anfrage an / db / question 300 Multiple Choices mit Link-Headern zurück, die angeben, wie zu jeder Seite [..] gelangt wird. Das Problem dabei (und bei den meisten reinen REST-Designs) ist, dass die Latenz beendet wird. Ziel ist es, Netzwerkanforderungen zu minimieren. Diese erste Anfrage sollte zu Ergebnissen führen und nicht zu weiteren Anfragen, die letztendlich die Daten liefern, die wir benötigen.
Stijn de Witt
4

Bearbeiten:

Nachdem ich ein bisschen mehr darüber nachgedacht habe, bin ich geneigt zuzustimmen, dass Range-Header nicht für die Paginierung geeignet sind. Die Logik ist, dass der Range-Header für die Antwort des Servers vorgesehen ist, nicht für die Anwendungen. Wenn Sie 100 Megabyte an Ergebnissen bereitgestellt haben, der Server (oder Client) jedoch jeweils nur 1 Megabyte verarbeiten konnte, ist dies der Zweck des Range-Headers.

Ich bin auch der Meinung, dass eine Teilmenge von Ressourcen eine eigene Ressource ist (ähnlich der relationalen Algebra), daher verdient sie die Darstellung in der URL.

Im Grunde genommen widerrufe ich meine ursprüngliche Antwort (unten) über die Verwendung eines Headers.


Ich denke, Sie haben Ihre eigene Frage mehr oder weniger beantwortet - geben Sie 200 oder 206 mit Inhaltsbereich zurück und verwenden Sie optional einen Abfrageparameter. Ich würde den Benutzeragenten und den Inhaltstyp beschnüffeln und, abhängig von diesen, nach einem Abfrageparameter suchen. Andernfalls benötigen Sie die Bereichskopfzeilen.

Sie haben im Wesentlichen widersprüchliche Ziele: Lassen Sie die Benutzer ihren Browser zum Erkunden verwenden (was benutzerdefinierte Header nicht einfach zulässt), oder zwingen Sie die Benutzer, einen speziellen Client zu verwenden, der Header festlegen kann (der sie nicht untersuchen lässt).

Sie können ihnen je nach Anforderung einfach den speziellen Client zur Verfügung stellen. Wenn es wie ein einfacher Browser aussieht, senden Sie eine kleine Ajax-App, die die Seite rendert und die erforderlichen Überschriften festlegt.

Natürlich gibt es auch die Debatte darüber, ob die URL den gesamten erforderlichen Status für solche Dinge enthalten soll. Das Festlegen des Bereichs mithilfe von Headern kann von einigen als "nicht erholsam" angesehen werden.

Abgesehen davon wäre es schön, wenn Server mit einem "Can-Specify: Header1, Header2" -Header antworten könnten und Webbrowser eine Benutzeroberfläche präsentieren würden, damit Benutzer auf Wunsch Werte eingeben könnten.

Richard Levasseur
quelle
Danke für die Antwort. Ich habe über das Thema nachgedacht, aber gehofft, eine zweite Meinung zu bekommen. Haben Sie einen Zeiger für die Header-Argumente?
Karl Guertin
Hier ist die einzige, die ich mit einem Lesezeichen versehen habe (siehe die Diskussion in den Kommentaren): kaumenough.org/blog/2008/05/versioning-rest-web-services Eine andere Website drehte sich um Rubys Verwendung von .json, .xml, .was auch immer bei der Bestimmung der Inhaltstyp einer Anfrage. Einige Beispiele: * Sprache - Wenn Sie den Link in die URL einfügen, wird der Link in ein anderes Land gesendet und in der falschen Sprache angezeigt. * Paginierung - Wenn Sie es in die Kopfzeile einfügen, können Sie keine Personen mit dem verknüpfen, was Sie sehen
Richard Levasseur
* Inhaltstyp: Eine Kombination aus Sprach- und Paginierungsproblemen. Wenn dies in der URL enthalten ist, was passiert, wenn der Client diesen Inhaltstyp nicht unterstützt (z. B. eine .ajax- und eine .html-Erweiterung)? Umgekehrt können Sie ohne diesen Inhaltstyp in der URL nicht sicherstellen, dass dieselbe Darstellung angegeben wird. "Neue Ajax-Site! example.com/cool.ajax" vs "cooler Artikel hier: example.com/article.ajax#id=123".
Richard Levasseur
2
IMO, ob es in der URL steht oder nicht, hängt davon ab, was es ist. Meine allgemeine Regel lautet: Wenn eine konkrete Ressource identifiziert werden soll (sei es eine Ressource in einem bestimmten Status, eine Auswahl von Ressourcen oder ein diskretes Ergebnis), wird sie in die URL aufgenommen. Suchanfragen, Paginierung und erholsame Transaktionen sind gute Beispiele dafür. Wenn es etwas ist, das benötigt wird, um die abstrakte Darstellung in eine konkrete Darstellung umzuwandeln, wird es in die Kopfzeile eingefügt. Auth-Info und Inhaltstyp sind gute Beispiele dafür.
Richard Levasseur
Ich stelle mir die Abfragezeichenfolge in einer URL als Optionen zum Abfragen der angegebenen Ressource vor.
wprl
3

Sie könnten in Betracht ziehen, ein Modell wie das Atom Feed Protocol zu verwenden, da es ein vernünftiges HTTP-Modell für Sammlungen enthält und wie man sie manipuliert (wobei verrückt WebDAV bedeutet).

Es gibt das Atom Publishing-Protokoll , das das Sammlungsmodell und die REST-Vorgänge definiert. Außerdem können Sie mit RFC 5005 - Feed Paging and Archiving große Sammlungen durchsuchen .

Der Wechsel von Atom XML zu JSON-Inhalten sollte die Idee nicht beeinflussen.

dajobe
quelle
3

Ich denke, das eigentliche Problem hier ist, dass die Spezifikation nichts enthält, was uns sagt, wie automatische Weiterleitungen durchgeführt werden sollen, wenn 413 - Angeforderte Entität zu groß ist.

Ich hatte kürzlich mit demselben Problem zu kämpfen und suchte nach Inspiration im RESTful Web Services- Buch. Persönlich halte ich 206 aufgrund der Header-Anforderung nicht für angemessen. Meine Gedanken führten mich auch zu 300, aber ich dachte, das wäre mehr für verschiedene MIME-Typen, also habe ich nachgeschlagen, was Richardson und Ruby zu diesem Thema in Anhang B, Seite 377 zu sagen hatten. Sie schlagen vor, dass der Server nur den bevorzugten auswählt Darstellung und senden Sie es mit einer 200 zurück, wobei Sie im Grunde die Vorstellung ignorieren, dass es eine 300 sein sollte.

Das stimmt auch mit der Vorstellung von Links zu den nächsten Ressourcen überein, die wir von Atom haben. Die Lösung, die ich implementiert habe, bestand darin, der json-Karte, die ich zurückgesendet habe, "nächste" und "vorherige" Schlüssel hinzuzufügen und damit fertig zu sein.

Später begann ich zu überlegen, ob ich vielleicht eine 307 - Temporäre Weiterleitung an einen Link senden sollte, der so etwas wie / db / question / 1,25 wäre -, der die ursprüngliche URI als kanonischen Ressourcennamen belässt, aber Sie dazu bringt eine entsprechend benannte untergeordnete Ressource. Dies ist ein Verhalten, das ich gerne von einem 413 sehen würde, aber 307 scheint ein guter Kompromiss zu sein. Ich habe dies jedoch noch nicht im Code versucht. Noch besser wäre es, wenn die Umleitung zu einer URL umleitet, die die tatsächlichen IDs der zuletzt gestellten Fragen enthält. Wenn beispielsweise jede Frage eine Ganzzahl-ID hat und 100 Fragen im System vorhanden sind und Sie die zehn neuesten anzeigen möchten, sollten die Anforderungen an / db / question 307 an / db / question / 100,91 gesendet werden

Dies ist eine sehr gute Frage, danke, dass Sie sie gestellt haben. Sie haben mir bestätigt, dass ich nicht verrückt bin, weil ich tagelang darüber nachgedacht habe.

stinkymatt
quelle
303 wäre in dieser Hinsicht besser als 307. 307 impliziert, dass die ursprüngliche URL bald wie vom Client erwartet reagiert.
Nicholas Shanks
RFC 7231 verweist auf den HTTP-Statuscode 413 als Payload Too Large und verknüpft diesen Code mit der Anforderungsgröße und nicht mit der potenziellen Antwortgröße.
Beawolf
1

Sie können den RangeHeader erkennen und Dojo imitieren, wenn es vorhanden ist, und Atom imitieren, wenn es nicht vorhanden ist. Es scheint mir, dass dies die Anwendungsfälle ordentlich unterteilt. Wenn Sie auf eine REST-Abfrage aus Ihrer Anwendung antworten, erwarten Sie, dass diese mit einem RangeHeader formatiert wird . Wenn Sie auf einen gelegentlichen Browser antworten und Paging-Links zurückgeben, bietet das Tool eine einfache Möglichkeit, die Sammlung zu erkunden.

Greg
quelle
1

Eines der großen Probleme bei Range-Headern besteht darin, dass viele Unternehmens-Proxys sie herausfiltern. Ich würde empfehlen, stattdessen einen Abfrageparameter zu verwenden.

user64141
quelle
0

Mir scheint, dass der beste Weg, dies zu tun, darin besteht, den Bereich als Abfrageparameter einzuschließen. zB GET / db / question /? date> mindate & date <maxdate . Bei einem GET zu / db / question / ohne Abfrageparameter geben Sie 303 mit dem Speicherort: / db / question /? Query-parameters-to-Retrieve-the-default-page zurück . Geben Sie dann eine andere URL an, unter der derjenige, der Ihre API verwendet, um Statistiken über die Sammlung abzurufen (z. B. welche Abfrageparameter verwendet werden sollen, wenn er die gesamte Sammlung haben möchte).

Dathan
quelle
0

Obwohl es möglich ist, den Range-Header für diesen Zweck zu verwenden, glaube ich nicht, dass dies die Absicht war. Es scheint für den Umgang mit flockigen Verbindungen sowie für die Begrenzung der Daten konzipiert worden zu sein (sodass der Client einen Teil der Anfrage anfordern kann, wenn etwas fehlte oder die Größe zu groß für die Verarbeitung war). Sie hacken die Paginierung in etwas, das wahrscheinlich für andere Zwecke auf der Kommunikationsebene verwendet wird. Die "richtige" Art, mit Paginierung umzugehen, sind die Typen, die Sie zurückgeben. Anstatt ein Fragenobjekt zurückzugeben, sollten Sie stattdessen einen neuen Typ zurückgeben.

Also, wenn Fragen so sind:

<questions> <question index=1></question> <question index=2></question> ... </questions>

Der neue Typ könnte ungefähr so ​​aussehen:

<questionPage> <startIndex>50</startIndex> <returnedCount>10</returnedCount> <totalCount>1203</totalCount> <questions> <question index=50></question> <question index=51></question> .. </questions> <questionPage>

Natürlich steuern Sie Ihre Medientypen, damit Sie Ihre "Seiten" zu einem Format machen können, das Ihren Anforderungen entspricht. Wenn Sie etwas generisches machen, können Sie einen einzelnen Parser auf dem Client haben, um das Paging für alle Typen gleich zu behandeln. Ich denke, das ist eher im Sinne der HTTP-Spezifikation, als den Range-Parameter für etwas anderes zu verfälschen.

jeremyh
quelle