Angenommen, auf einem System befindet sich eine Webanwendung mit einer Ressource und ein Verweis auf eine Remoteanwendung mit einer anderen ähnlichen Ressource. Wie stellen Sie eine bidirektionale Synchronisierungsaktion dar, mit der die "lokale" Ressource mit der "Remoteressource" synchronisiert wird?
Beispiel:
Ich habe eine API, die eine Aufgabenliste darstellt.
GET / POST / PUT / DELETE / Aufgaben / usw.
Diese API kann auf entfernte TODO-Dienste verweisen.
GET / POST / PUT / DELETE / todo_services / usw.
Ich kann Aufgaben vom Remote-Service über meine API als Proxy über bearbeiten
GET / POST / PUT / DELETE / todo_services / abc123 / usw.
Ich möchte die Möglichkeit haben, eine bidirektionale Synchronisierung zwischen einer lokalen Gruppe von Aufgaben und der Remote-Gruppe von TODOS durchzuführen.
In gewisser Weise könnte man das tun
POST / todo_services / abc123 / sync /
Aber gibt es in der Idee "Verben sind schlecht" eine bessere Möglichkeit, diese Aktion darzustellen?
quelle
GET /todo/1/
undPOST
It/todo_services/abc123/
To. Aber die 2-Wege-Methode - Ich nehme keinen Datensatz und lege ihn in eine Ressource um. Die von mir ausgeführte Aktion führt tatsächlich zu einer möglichen Änderung von zwei Ressourcen. Ich schätze, ich könnte darauf zurückgreifen, dass "Syncronizations" selbst Ressourcen sindPOST /todo_synchronizations/ {"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now"}
GET /todo_synchronizations/1
=>{"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now","ran_at":"datetime","result":"success"}
Antworten:
Wo und was sind die Ressourcen?
Bei REST geht es darum, Ressourcen auf zustandslose, erkennbare Weise anzusprechen. Es muss weder über HTTP implementiert werden, noch muss es sich auf JSON oder XML stützen. Es wird jedoch dringend empfohlen, ein Hypermedia-Datenformat zu verwenden (siehe das HATEOAS- Prinzip), da Links und IDs wünschenswert sind.
Die Frage lautet also: Wie denkt man über Synchronisation in Bezug auf Ressourcen?
Was ist bidirektionale Synchronisierung? **
Bei der bidirektionalen Synchronisierung werden die in einem Knotendiagramm vorhandenen Ressourcen aktualisiert, sodass am Ende des Prozesses alle Knoten ihre Ressourcen gemäß den Regeln für diese Ressourcen aktualisiert haben. In der Regel bedeutet dies, dass auf allen Knoten die aktuellste Version der Ressourcen im Diagramm vorhanden ist. Im einfachsten Fall besteht der Graph aus zwei Knoten: lokal und entfernt. Lokal initiiert die Synchronisierung.
Die Schlüsselressource, die angesprochen werden muss, ist also ein Transaktionsprotokoll. Daher könnte ein Synchronisierungsprozess für die Auflistung "items" unter HTTP folgendermaßen aussehen:
Schritt 1 - Lokal ruft das Transaktionsprotokoll ab
Lokal:
GET /remotehost/items/transactions?earliest=2000-01-01T12:34:56.789Z
Remote: 200 OK, wobei der Body ein Transaktionsprotokoll enthält, das ähnliche Felder enthält.
itemId
- eine UUID zur Bereitstellung eines gemeinsam genutzten PrimärschlüsselsupdatedAt
- Zeitstempel, um einen koordinierten Zeitpunkt für die letzte Aktualisierung der Daten anzugeben (vorausgesetzt, ein Änderungsverlauf ist nicht erforderlich)fingerprint
- Ein SHA1-Hash des Dateninhalts zum schnellen Vergleich, wennupdateAt
einige Sekunden vergangen sinditemURI
- eine vollständige URI für den Artikel, um ihn später abrufen zu könnenSchritt 2 - Local vergleicht das Remote-Transaktionsprotokoll mit seinem eigenen
Dies ist die Anwendung der Geschäftsregeln für die Synchronisierung. In der Regel
itemId
wird die lokale Ressource identifiziert und anschließend der Fingerabdruck verglichen. Wenn es einen Unterschied gibt, wird ein Vergleich von durchgeführtupdatedAt
. Wenn diese zu nah am Anruf sind, muss eine Entscheidung getroffen werden, basierend auf dem anderen Knoten zu ziehen (vielleicht ist es wichtiger) oder auf den anderen Knoten zu pushen (dieser Knoten ist wichtiger). Wenn die Remote-Ressource nicht lokal vorhanden ist, wird ein Push-Eintrag vorgenommen (dieser enthält die tatsächlichen Daten zum Einfügen / Aktualisieren). Alle lokalen Ressourcen, die nicht im Remote-Transaktionsprotokoll vorhanden sind, werden als unverändert angenommen.Die Pull-Anforderungen werden an den Remote-Knoten gesendet, sodass die Daten lokal über den vorhanden sind
itemURI
. Sie werden erst später lokal angewendet.Schritt 3 - Lokales Synchronisationstransaktionsprotokoll an Remote senden
Lokal:
PUT /remotehost/items/transactions
mit Hauptteil, der das lokale Synchronisierungstransaktionsprotokoll enthält.Der entfernte Knoten kann diese synchron verarbeiten (wenn es klein und schnell) oder asynchron (man denke an 202 AKZEPTIERT ) , wenn es wahrscheinlich ist , eine Menge Aufwand entstehen. Unter der Annahme einer synchronen Operation lautet das Ergebnis je nach Erfolg oder Misserfolg entweder 200 OK oder 409 CONFLICT . Bei einem 409 CONFLICT muss der Prozess erneut gestartet werden, da auf dem Remote-Knoten ein optimistischer Sperrfehler aufgetreten ist (jemand hat die Daten während der Synchronisierung geändert). Die Fernaktualisierungen werden unter ihrer eigenen Anwendungstransaktion verarbeitet.
Schritt 4 - Lokal aktualisieren
Die in Schritt 2 abgerufenen Daten werden lokal im Rahmen einer Anwendungstransaktion angewendet.
Das oben Genannte ist zwar nicht perfekt (es gibt mehrere Situationen, in denen lokale und entfernte Geräte Probleme verursachen können und das Abrufen von Daten von lokalen Geräten wahrscheinlich effizienter ist als das Einfügen in einen großen PUT), es zeigt jedoch, wie REST während eines Bi- Richtungssynchronisationsprozess.
quelle
Ich würde einen Synchronisierungsvorgang als Ressource betrachten, auf die zugegriffen werden kann (GET) oder die erstellt werden kann (POST). In diesem Sinne könnte die API-URL sein:
(Nennen wir es "Synchronisation", nicht "Synchronisation", um deutlich zu machen, dass es kein Verb ist.)
Dann mach:
Eine Synchronisation einleiten. Da eine Synchronisierungsoperation eine Ressource ist, kann dieser Aufruf möglicherweise eine ID zurückgeben, mit der der Status der Operation überprüft werden kann:
quelle
Das ist ein schweres Problem. Ich glaube nicht, dass REST eine angemessene Ebene ist, um die Synchronisierung zu implementieren. Eine robuste Synchronisierung müsste im Wesentlichen eine verteilte Transaktion sein. REST ist nicht das Werkzeug für diesen Job.
(Annahme: Durch "Synchronisieren" wird impliziert, dass sich eine Ressource jederzeit unabhängig von der anderen ändern kann und Sie sie neu ausrichten möchten, ohne dass Aktualisierungen verloren gehen.)
Sie können erwägen, einen zum "Master" und einen zum "Slave" zu machen, damit Sie den Slave in regelmäßigen Abständen mit Daten vom Master souverän überlasten können.
Sie können auch das Microsoft Sync Framework in Betracht ziehen, wenn Sie das unabhängige Ändern von Datenspeichern unbedingt unterstützen müssen. Dies würde nicht über REST funktionieren, sondern hinter den Kulissen.
quelle
Apache CouchDB ist eine Datenbank, die auf REST, HTTP und JSON basiert. Entwickler führen grundlegende CRUD-Operationen über HTTP durch. Es bietet auch einen Replikationsmechanismus, der Peer-to-Peer ist und nur HTTP-Methoden verwendet.
Um diese Replikation bereitzustellen, muss CouchDB über einige CouchDB-spezifische Konventionen verfügen. Keines von diesen ist gegen REST. Es versieht jedes Dokument (das eine REST-Ressource in einer Datenbank ist) mit einer Revisionsnummer . Dies ist Teil der JSON-Darstellung dieses Dokuments, befindet sich jedoch auch im ETag-HTTP-Header. Jede Datenbank verfügt auch über eine Sequenznummer, mit der Änderungen an der gesamten Datenbank verfolgt werden können.
Bei der Konfliktlösung stellen sie einfach fest, dass ein Dokument in Konflikt steht, und behalten die in Konflikt stehenden Versionen bei. Überlassen Sie es den Entwicklern, die die Datenbank verwenden, um einen Konfliktlösungsalgorithmus bereitzustellen.
Sie können entweder CouchDB als REST-API verwenden, mit der Sie sofort synchronisiert werden können, oder sich die Replikation ansehen, um einen Ausgangspunkt für die Erstellung Ihres eigenen Algorithmus zu finden.
quelle
Sie können das Problem "Verben sind schlecht" durch einfaches Umbenennen lösen. Verwenden Sie "Updates" anstelle von "Synchronisieren".
Der Synchronisierungsprozess sendet tatsächlich eine Liste der lokalen Aktualisierungen, die seit der letzten Synchronisierung vorgenommen wurden, und empfängt gleichzeitig eine Liste der auf dem Server vorgenommenen Aktualisierungen.
quelle