Dies ist eine allgemeinere Neuformulierung dieser Frage (unter Eliminierung der Rails-spezifischen Teile).
Ich bin nicht sicher, wie ich die Paginierung einer Ressource in einer RESTful-Webanwendung implementieren soll. Angenommen, ich habe eine Ressource namens products
, welche der folgenden Methoden ist Ihrer Meinung nach der beste und warum:
1. Verwenden Sie nur Abfragezeichenfolgen
z.B. http://application/products?page=2&sort_by=date&sort_how=asc
Das Problem hierbei ist, dass ich kein Ganzseiten-Caching verwenden kann und auch die URL nicht sehr sauber und leicht zu merken ist.
2. Verwenden von Seiten als Ressourcen und Abfragezeichenfolgen zum Sortieren
z.B. http://application/products/page/2?sort_by=date&sort_how=asc
In diesem Fall besteht das Problem darin, dass http://application/products/pages/1
es sich nicht um eine eindeutige Ressource handelt, da die Verwendung zu sort_by=price
einem völlig anderen Ergebnis führen kann und ich das Seiten-Caching immer noch nicht verwenden kann.
3. Verwenden von Seiten als Ressourcen und eines URL-Segments zum Sortieren
z.B. http://application/products/by-date/page/2
Ich persönlich sehe kein Problem bei der Verwendung dieser Methode, aber jemand hat mich gewarnt, dass dies kein guter Weg ist (er hat keinen Grund angegeben. Wenn Sie also wissen, warum dies nicht empfohlen wird, lassen Sie es mich bitte wissen.)
Irgendwelche Vorschläge, Meinungen, Kritiken sind mehr als willkommen. Vielen Dank.
quelle
Antworten:
Ich denke, das Problem mit Version 3 ist eher ein "Standpunkt" -Problem - sehen Sie die Seite als Ressource oder als Produkte auf der Seite?
Wenn Sie die Seite als Ressource sehen, ist dies eine perfekte Lösung, da die Abfrage für Seite 2 immer Seite 2 ergibt.
Wenn Sie jedoch die Produkte auf der Seite als Ressource sehen, besteht das Problem, dass sich die Produkte auf Seite 2 ändern (alte Produkte gelöscht oder was auch immer). In diesem Fall gibt der URI nicht immer dieselben Ressourcen zurück.
Beispiel: Ein Kunde speichert einen Link zur Produktlistenseite X. Beim nächsten Öffnen des Links befindet sich das betreffende Produkt möglicherweise nicht mehr auf Seite X.
quelle
Ich stimme Fionn zu, aber ich werde noch einen Schritt weiter gehen und sagen, dass die Seite für mich keine Ressource ist, sondern eine Eigenschaft der Anfrage. Aus diesem Grund habe ich nur die Abfragezeichenfolge für Option 1 ausgewählt. Es fühlt sich einfach richtig an. Mir gefällt sehr, wie die Twitter-API restauriert ist. Nicht zu einfach, nicht zu kompliziert, gut dokumentiert. Ob gut oder schlecht, es ist mein "Gehe zu" -Design, wenn ich auf dem Zaun bin, um etwas in die eine oder andere Richtung zu tun.
quelle
HTTP hat einen großartigen Range-Header, der auch für die Paginierung geeignet ist. Sie können senden
nur die erste Seite haben. Das kann Sie dazu zwingen, eine Seite zu überdenken. Vielleicht möchte der Kunde eine andere Auswahl an Artikeln. Der Bereichskopf deklariert auch eine Bestellung:
um alle Produkte neuer als dieses Datum zu bekommen oder
um alle Produkte älter als dieses Datum zu bekommen. '0' ist wahrscheinlich nicht die beste Lösung, aber RFC scheint etwas für den Bereichsstart zu wollen. Möglicherweise werden HTTP-Parser bereitgestellt, die die Einheiten = -range_end nicht analysieren.
Wenn Header keine (akzeptable) Option sind, denke ich, dass die erste Lösung (alle in Abfragezeichenfolge) eine Möglichkeit ist, mit Seiten umzugehen. Normalisieren Sie jedoch die Abfragezeichenfolgen (sortieren Sie (Schlüssel = Wert) Paare in alphabetischer Reihenfolge). Dies löst das Differenzierungsproblem "? A = 1 & b = x" und "? B = x & a = 1".
quelle
range-unit = bytes-unit | other-range-unit
Vielleicht beziehen Sie sich aufThe only range unit defined by HTTP/1.1 is "bytes". HTTP/1.1 implementations MAY ignore ranges specified using other units.
Das ist nicht dasselbe wie Ihre Aussage.Option 1 scheint insofern am besten zu sein, als Ihre Anwendung die Paginierung als eine Technik zum Erstellen einer anderen Ansicht derselben Ressource betrachtet.
Allerdings ist das URL-Schema relativ unbedeutend. Wenn Sie Ihre Anwendung so gestalten, dass sie hypertextgesteuert ist (da alle REST-Anwendungen per Definition sein müssen), erstellt Ihr Client keine eigenen URIs. Stattdessen gibt Ihre Anwendung die Links zum Client an und der Client folgt ihnen.
Eine Art von Link, den Ihr Kunde bereitstellen kann, ist ein Paginierungslink.
Der angenehme Nebeneffekt all dessen ist, dass Ihre Kunden, selbst wenn Sie Ihre Meinung zur Paginierungs-URI-Struktur ändern und nächste Woche etwas völlig anderes implementieren, ohne Änderungen weiterarbeiten können.
quelle
Ich habe immer den Stil von Option 1 verwendet. Das Zwischenspeichern war kein Problem, da sich die Daten in meinem Fall ohnehin häufig ändern. Wenn Sie zulassen, dass die Größe der Seite konfiguriert werden kann, können die Daten erneut nicht zwischengespeichert werden.
Ich finde die URL nicht schwer zu merken oder unrein. Für mich ist dies eine gute Verwendung von Abfrageparametern. Die Ressource ist eindeutig eine Liste von Produkten, und die Abfrageparameter geben nur an, wie die Liste angezeigt werden soll - sortiert und auf welcher Seite.
quelle
Seltsam, dass niemand darauf hingewiesen hat, dass Option 3 Parameter in einer bestimmten Reihenfolge hat. http // application / products / Date / Descending / Name / Ascending / page / 2 und http // application / products / Name / Ascending / Date / Descending / page / 2
verweisen auf dieselbe Ressource, haben jedoch völlig unterschiedliche URLs.
Für mich scheint Option 1 die akzeptabelste zu sein, da sie "Was ich will" und "Wie ich will" klar voneinander trennt (es hat sogar ein Fragezeichen zwischen ihnen lol). Das Ganzseiten-Caching kann unter Verwendung der vollständigen URL implementiert werden (alle Optionen haben ohnehin das gleiche Problem).
Beim Parameters-in-URL-Ansatz ist der einzige Vorteil eine saubere URL. Sie müssen sich jedoch eine Möglichkeit einfallen lassen, um Parameter zu codieren und verlustfrei zu decodieren. Natürlich kannst du mit URLencode / Decode gehen, aber es wird URLs wieder hässlich machen :)
quelle
Ich würde es vorziehen, die Abfrageparameter Offset und Limit zu verwenden.
Offset : für den Index des Elements in der Sammlung.
Limit : für die Anzahl der Artikel.
Der Client kann den Offset einfach wie folgt aktualisieren
für die nächste Seite.
Der Pfad wird als Ressourcenkennung betrachtet. Und eine Seite ist keine Ressource, sondern eine Teilmenge der Ressourcensammlung. Da die Paginierung im Allgemeinen eine GET-Anforderung ist, eignen sich Abfrageparameter eher für die Paginierung als für Header.
Referenz: https://metamug.com/article/rest-api-developers-dilemma.html#Requesting-the-next-page
quelle
Auf der Suche nach Best Practices bin ich auf diese Website gestoßen:
http://www.restapitutorial.com
Auf der Ressourcenseite befindet sich ein Link zum Herunterladen einer PDF-Datei, die die vollständigen, vom Autor vorgeschlagenen REST-Best Practices enthält. In dem es unter anderem einen Abschnitt über Paginierung gibt.
Der Autor schlägt vor, sowohl die Verwendung eines Range-Headers als auch die Verwendung von Abfragezeichenfolgenparametern zu unterstützen.
Anfrage
Beispiel für einen HTTP-Header:
Beispiel für Abfragezeichenfolgenparameter:
Wobei Offset die anfängliche Artikelnummer und das Limit ist die maximale Anzahl der zurückzugebenden Artikel.
Antwort
Die Antwort sollte einen Content-Range-Header enthalten, der angibt, wie viele Elemente zurückgegeben werden und wie viele Elemente insgesamt noch abgerufen werden müssen
Beispiele für HTTP-Header:
In der PDF-Datei finden Sie einige weitere Vorschläge für spezifischere Fälle.
quelle
Ich verwende derzeit ein ähnliches Schema in meinen ASP.NET MVC-Apps:
z.B
http://application/products/by-date/page/2
speziell ist es:
http://application/products/Date/Ascending/3
Ich bin jedoch nicht wirklich zufrieden damit, Paging- und Sortierinformationen auf diese Weise in die Route aufzunehmen.
Die Liste der Artikel (in diesem Fall Produkte) ist veränderbar. Wenn jemand das nächste Mal zu einer URL zurückkehrt, die Paging- und Sortierparameter enthält, haben sich die Ergebnisse möglicherweise geändert. Die Idee
http://application/products/Date/Ascending/3
einer eindeutigen URL, die auf eine definierte, unveränderliche Reihe von Produkten verweist, geht also verloren.quelle
Ich stimme slf eher zu, dass "Seite" nicht wirklich eine Ressource ist. Auf der anderen Seite ist Option 3 sauberer, leichter zu lesen und kann vom Benutzer leichter erraten und bei Bedarf sogar abgetippt werden. Ich bin zwischen Option 1 und 3 hin und her gerissen, sehe aber keinen Grund, Option 3 nicht zu verwenden.
Auch wenn sie gut aussehen, besteht ein Nachteil der Verwendung versteckter Parameter, wie bereits erwähnt, anstelle von Abfragezeichenfolgen oder URL-Segmenten darin, dass der Benutzer keine Lesezeichen setzen oder direkt auf eine bestimmte Seite verlinken kann. Dies kann je nach Anwendung ein Problem sein oder auch nicht, aber nur etwas, das Sie beachten sollten.
quelle
Ich habe schon einmal Lösung 3 verwendet (ich schreibe eine Menge Django-Apps). Und ich glaube nicht, dass daran etwas falsch ist. Es ist genauso generierbar wie die beiden anderen (falls Sie etwas Massenkratzen oder ähnliches durchführen müssen) und es sieht sauberer aus. Außerdem können Ihre Benutzer URLs erraten (wenn es sich um eine öffentlich zugängliche App handelt), und die Leute mögen es, direkt dorthin zu gelangen, wo sie wollen, und das Erraten von URLs fühlt sich befähigend an.
quelle
Ich verwende in meinen Projekten die folgenden URLs:
was bedeutet - "gib mir Seite die zweite Seite geordnet nach Feld1 und dann nach Feld2 absteigend". Oder wenn ich noch mehr Flexibilität brauche, benutze ich:
quelle
Ich verwende in folgenden Mustern, um den nächsten Seitendatensatz zu erhalten. http: // application / products? lastRecordKey =? & pageSize = 20 & sort = ASC
RecordKey ist die Spalte einer Tabelle, die einen sequentiellen Wert in DB enthält. Dies wird verwendet, um jeweils nur eine Seitendaten aus der Datenbank abzurufen. Mit pageSize wird festgelegt, wie viele Datensätze abgerufen werden sollen. sort wird verwendet, um den Datensatz in aufsteigender oder absteigender Reihenfolge zu sortieren.
quelle