Welche bewährten Entwurfsmuster gibt es für Stapeloperationen an Ressourcen innerhalb eines Webdienstes im REST-Stil?
Ich versuche, ein Gleichgewicht zwischen Idealen und Realität in Bezug auf Leistung und Stabilität zu finden. Wir haben derzeit eine API, in der alle Vorgänge entweder von einer Listenressource (dh GET / user) oder von einer einzelnen Instanz (PUT / user / 1, DELETE / user / 22 usw.) abgerufen werden.
In einigen Fällen möchten Sie ein einzelnes Feld einer ganzen Reihe von Objekten aktualisieren. Es erscheint sehr verschwenderisch, die gesamte Darstellung für jedes Objekt hin und her zu senden, um das eine Feld zu aktualisieren.
In einer API im RPC-Stil könnten Sie eine Methode haben:
/mail.do?method=markAsRead&messageIds=1,2,3,4... etc.
Was ist das REST-Äquivalent hier? Oder ist es in Ordnung, ab und zu Kompromisse einzugehen? Ruiniert es das Design, einige spezifische Vorgänge hinzuzufügen, bei denen die Leistung usw. wirklich verbessert wird? Der Client ist derzeit in allen Fällen ein Webbrowser (Javascript-Anwendung auf der Clientseite).
quelle
PATCH
- in diesem Fall ist keine Kreativität erforderlich.Überhaupt nicht - ich denke, das REST-Äquivalent ist (oder zumindest eine Lösung ist) fast genau das - eine spezielle Schnittstelle, die für eine vom Client geforderte Operation ausgelegt ist.
Ich erinnere mich an ein Muster, das in Crane und Pascarellos Buch Ajax in Action erwähnt wurde (übrigens ein ausgezeichnetes Buch - sehr zu empfehlen), in dem sie die Implementierung einer CommandQueue veranschaulichen Objekts dessen Aufgabe es ist, Anforderungen in Stapel und in eine Warteschlange zu stellen Dann poste sie regelmäßig auf dem Server.
Wenn ich mich richtig erinnere, enthielt das Objekt im Wesentlichen nur ein Array von "Befehlen" - z. B. um Ihr Beispiel zu erweitern, jedes einen Datensatz, der einen "markAsRead" -Befehl, eine "messageId" und möglicherweise einen Verweis auf einen Rückruf / Handler enthält Funktion - und dann würde das Befehlsobjekt gemäß einem Zeitplan oder einer Benutzeraktion serialisiert und auf den Server gebucht, und der Client würde die konsequente Nachbearbeitung übernehmen.
Ich habe die Details nicht zur Hand, aber es klingt so, als ob eine Befehlswarteschlange dieser Art eine Möglichkeit wäre, Ihr Problem zu lösen. Dies würde die allgemeine Chattiness erheblich reduzieren und die serverseitige Benutzeroberfläche auf eine Weise abstrahieren, die Sie später möglicherweise flexibler finden.
Update : Aha! Ich habe online einen Ausschnitt aus diesem Buch gefunden, der Codebeispiele enthält (obwohl ich immer noch vorschlage, das eigentliche Buch abzuholen!). Schauen Sie hier , beginnend mit Abschnitt 5.5.3:
Hier sind zwei relevante Funktionen - eine für das Hinzufügen von Befehlen zur Warteschlange (
addCommand
) und eine für das Serialisieren und anschließende Senden an den Server (fireRequest
):Das sollte dich zum Laufen bringen. Viel Glück!
quelle
Während ich denke, dass @Alex auf dem richtigen Weg ist, denke ich, dass es konzeptionell das Gegenteil von dem sein sollte, was vorgeschlagen wird.
Die URL ist in der Tat "die Ressourcen, auf die wir abzielen", daher:
bedeutet, den Datensatz von Mail mit ID 1 und zu erhalten
bedeutet, den Mail-Datensatz mit der ID 1 zu patchen. Der Querystring ist ein "Filter", der die von der URL zurückgegebenen Daten filtert.
Hier fordern wir also alle E-Mails an, die bereits als gelesen markiert sind. Zu [PATCH] auf diesen Pfad zu gehen würde also bedeuten, "die bereits als wahr markierten Datensätze zu patchen " ... was wir nicht erreichen wollen.
Eine Batch-Methode, die diesem Gedanken folgt, sollte also sein:
Natürlich sage ich nicht, dass dies echtes REST ist (was keine Manipulation von Batch-Datensätzen erlaubt), sondern es folgt der Logik, die bereits existiert und von REST verwendet wird.
quelle
[GET]
zu erledigenden Format[PATCH] mail?markAsRead=true data: [{"id": 1}, {"id": 2}, {"id": 3}]
(oder sogar nurdata: {"ids": [1,2,3]}
)? Ein weiterer Vorteil dieses alternativen Ansatzes besteht darin, dass beim Aktualisieren von Hunderten / Tausenden von Ressourcen in der Sammlung keine Fehler "414 Request URI too long" auftreten.Ihre Sprache "Es scheint sehr verschwenderisch ..." deutet auf einen Versuch einer vorzeitigen Optimierung hin. Wenn nicht gezeigt werden kann, dass das Senden der gesamten Darstellung von Objekten einen großen Leistungseinbruch darstellt (wir sprechen von Benutzern als> 150 ms inakzeptabel), macht es keinen Sinn, ein neues nicht standardmäßiges API-Verhalten zu erstellen. Denken Sie daran, je einfacher die API ist, desto einfacher ist ihre Verwendung.
Senden Sie zum Löschen Folgendes, da der Server vor dem Löschen nichts über den Status des Objekts wissen muss.
Der nächste Gedanke ist, dass, wenn bei einer Anwendung Leistungsprobleme in Bezug auf die Massenaktualisierung von Objekten auftreten, überlegt werden sollte, jedes Objekt in mehrere Objekte aufzuteilen. Auf diese Weise ist die JSON-Nutzlast ein Bruchteil der Größe.
Wenn Sie beispielsweise eine Antwort senden, um den Status "Lesen" und "Archiviert" von zwei separaten E-Mails zu aktualisieren, müssen Sie Folgendes senden:
Ich würde die veränderlichen Komponenten der E-Mail (Lesen, Archivieren, Wichtigkeit, Beschriftungen) in ein separates Objekt aufteilen, da die anderen (zu, von, Betreff, Text) niemals aktualisiert würden.
Ein weiterer Ansatz besteht darin, die Verwendung eines PATCH zu nutzen. Um explizit anzugeben, welche Eigenschaften Sie aktualisieren möchten und dass alle anderen ignoriert werden sollen.
Die Benutzer geben an, dass PATCH implementiert werden soll, indem eine Reihe von Änderungen bereitgestellt werden, die Folgendes enthalten: Aktion (CRUD), Pfad (URL) und Wertänderung. Dies kann als Standardimplementierung betrachtet werden. Wenn Sie sich jedoch die Gesamtheit einer REST-API ansehen, handelt es sich um eine nicht intuitive Einzelimplementierung. Mit der obigen Implementierung hat GitHub PATCH implementiert .
Zusammenfassend lässt sich sagen, dass es möglich ist, RESTful-Prinzipien mit Batch-Aktionen einzuhalten und dennoch eine akzeptable Leistung zu erzielen.
quelle
Die Google Drive API verfügt über ein wirklich interessantes System zur Lösung dieses Problems ( siehe hier ).
Grundsätzlich gruppieren sie verschiedene Anforderungen in einer
Content-Type: multipart/mixed
Anforderung, wobei jede einzelne vollständige Anforderung durch ein definiertes Trennzeichen getrennt ist. Header und Abfrageparameter der Stapelanforderung werden an die einzelnen Anforderungen (dhAuthorization: Bearer some_token
) vererbt, sofern sie nicht in der einzelnen Anforderung überschrieben werden.Beispiel : (aus ihren Dokumenten entnommen )
Anfrage:
Antwort:
quelle
Ich wäre in einer Operation wie der in Ihrem Beispiel versucht, einen Bereichsparser zu schreiben.
Es ist nicht sehr mühsam, einen Parser zu erstellen, der "messageIds = 1-3,7-9,11,12-15" lesen kann. Dies würde sicherlich die Effizienz für pauschale Vorgänge erhöhen, die alle Nachrichten abdecken, und ist skalierbarer.
quelle
Guter Eintrag. Ich habe seit ein paar Tagen nach einer Lösung gesucht. Ich habe eine Lösung gefunden, bei der eine Abfragezeichenfolge mit durch Kommas getrennten Bündel-IDs übergeben wird, z.
... dann übergebe das an eine
WHERE IN
Klausel in meinem SQL. Es funktioniert großartig, aber fragen Sie sich, was andere über diesen Ansatz denken.quelle
DELETE /books/delete?id=1,2,3
wenn Buch Nr. 3 nicht existiert - dasWHERE IN
ignoriert stillschweigend Datensätze, wohingegen ich normalerweiseDELETE /books/delete?id=3
404 erwarten würde , wenn 3 nicht existiert.Aus meiner Sicht denke ich, dass Facebook die beste Implementierung hat.
Eine einzelne HTTP-Anforderung wird mit einem Stapelparameter und einer für ein Token gestellt.
Im Batch wird ein JSON gesendet. welches eine Sammlung von "Anfragen" enthält. Jede Anforderung verfügt über eine Methodeneigenschaft (get / post / put / delete / etc ...) und eine relative_url-Eigenschaft (uri des Endpunkts). Zusätzlich ermöglichen die post- und put-Methoden eine "body" -Eigenschaft, in der die Felder aktualisiert werden sind gesendet .
Weitere Infos unter: Facebook Batch API
quelle