Quanto meglio rappresenti una sincronizzazione bidirezionale in un API REST?


23

Supponendo che un sistema in cui è presente un'applicazione Web con una risorsa e un riferimento a un'applicazione remota con un'altra risorsa simile, come rappresenti un'azione di sincronizzazione bidirezionale che sincronizzi la risorsa "locale" con la risorsa "remota"?

Esempio:

Ho un'API che rappresenta un elenco di cose da fare.

OTTIENI / POST / PUT / ELIMINA / todos /, ecc.

Tale API può fare riferimento a servizi TODO remoti.

OTTIENI / POST / PUT / ELIMINA / todo_services /, ecc.

Posso manipolare todos dal servizio remoto tramite la mia API come proxy tramite

OTTIENI / POST / PUT / ELIMINA / todo_services / abc123 /, ecc.

Voglio la possibilità di fare una sincronizzazione bidirezionale tra un set locale di todos e il set remoto di TODOS.

In un certo senso rpc, si potrebbe fare

POST / todo_services / abc123 / sync /

Ma nell'idea "i verbi sono cattivi", c'è un modo migliore per rappresentare questa azione?


4
Penso che una buona progettazione dell'API sia assolutamente dipendente da una comprensione molto concreta di ciò che intendi per sincronizzazione. La "sincronizzazione" di due origini dati è di solito un problema molto complesso che è semplicissimo da semplificare eccessivamente ma molto difficile da comprendere in tutte le sue implicazioni. Rendilo una sincronizzazione "bidirezionale" e improvvisamente la difficoltà è molto più alta. Inizia pensando alle domande molto difficili che sorgono.
Adam Crossland,

Bene - supponiamo che l'algoritmo di sincronizzazione sia progettato e funzionante nell'API "a livello di codice" - come posso esporlo tramite REST. La sincronizzazione in un modo sembra molto più facile da esprimere: io GET /todo/1/e POSTquesto a /todo_services/abc123/ Ma, in 2 modi: non sto prendendo un set di dati e METTENDO una risorsa, l'azione che sto effettivamente portando alla potenziale modifica di due risorse. Immagino di poter ricadere sull'avere "todo syncronization" come risorse stesse POST /todo_synchronizations/ {"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now"}
Edward M Smith,

Abbiamo ancora un problema con il carrello prima del cavallo. Il mio punto era che non puoi supporre che la sincronizzazione funzioni e progetti l'API. Il design dell'API sarà guidato da numerose preoccupazioni su come funziona esattamente l'algoritmo di sincronizzazione.
Adam Crossland,

Ciò potenzialmente rivela risultati utili: GET /todo_synchronizations/1=>{"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now","ran_at":"datetime","result":"success"}
Edward M Smith,

2
Sono d'accordo con @Adam. Sai come implementerai la tua sincronizzazione? Come gestite le modifiche? Hai semplicemente due insiemi di elementi che desideri riconciliare o hai un registro delle azioni che hanno fatto divergere i due insiemi dall'ultima sincronizzazione? Il motivo per cui chiedo è che può essere difficile rilevare aggiunte ed eliminazioni (indipendentemente da REST). Se hai un oggetto lato server e non lo hai lato client, devi chiederti: "Il client lo ha eliminato o lo ha creato il server?" Solo quando sai esattamente come si comporta la "risorsa" puoi rappresentarla accuratamente in REST.
Raymond Saltrelli,

Risposte:


17

Dove e quali sono le risorse?

REST si occupa di indirizzare le risorse in modo apolide e rilevabile. Non deve essere implementato su HTTP, né deve fare affidamento su JSON o XML, anche se si consiglia vivamente di utilizzare un formato dati ipermediale (vedere il principio HATEOAS ) poiché sono desiderabili collegamenti e ID.

Quindi, la domanda diventa: come si pensa alla sincronizzazione in termini di risorse?

Cos'è la sincronizzazione bidirezionale? **

La sincronizzazione bidirezionale è il processo di aggiornamento delle risorse presenti su un grafico di nodi in modo che, alla fine del processo, tutti i nodi abbiano aggiornato le proprie risorse in conformità con le regole che governano tali risorse. In genere, si ritiene che tutti i nodi dispongano dell'ultima versione delle risorse presenti nel grafico. Nel caso più semplice il grafico è costituito da due nodi: locale e remoto. Local avvia la sincronizzazione.

Quindi la risorsa chiave che deve essere indirizzata è un registro delle transazioni e, quindi, un processo di sincronizzazione potrebbe apparire così per la raccolta "articoli" sotto HTTP:

Passaggio 1: Local recupera il registro delle transazioni

Locale: GET /remotehost/items/transactions?earliest=2000-01-01T12:34:56.789Z

Remoto: 200 OK con corpo contenente il registro delle transazioni contenente campi simili a questo.

  • itemId - un UUID per fornire una chiave primaria condivisa

  • updatedAt - data / ora per fornire un punto coordinato in cui i dati sono stati aggiornati l'ultima volta (presupponendo che non sia richiesta una cronologia delle revisioni)

  • fingerprint- un hash SHA1 del contenuto dei dati per un rapido confronto se updateAtè fuori di pochi secondi

  • itemURI - un URI completo per l'articolo per consentire il recupero in un secondo momento

Passaggio 2: Local confronta il registro delle transazioni remote con il proprio

Questa è l'applicazione delle regole di business su come sincronizzare. In genere, itemIdidentifica la risorsa locale, quindi confronta l'impronta digitale. Se c'è una differenza, updatedAtviene effettuato un confronto di . Se questi sono troppo vicini per essere chiamati, sarà quindi necessario prendere una decisione in base all'altro nodo (forse è più importante) o passare all'altro nodo (questo nodo è più importante). Se la risorsa remota non è presente localmente, viene effettuata una voce push (contiene i dati effettivi per l'inserimento / aggiornamento). Si presume che qualsiasi risorsa locale non presente nel registro delle transazioni remote sia invariata.

Le richieste pull vengono fatte sul nodo remoto in modo che i dati esistano localmente usando il itemURI. Non vengono applicati localmente fino a dopo.

Passaggio 3: inviare il registro delle transazioni di sincronizzazione locale al remoto

Locale: PUT /remotehost/items/transactions con corpo contenente il registro delle transazioni di sincronizzazione locale.

Il nodo remoto potrebbe elaborarlo in modo sincrono (se è piccolo e veloce) o in modo asincrono (si pensi ad 202 ACCETTATO ) se è probabile che si verifichino molte spese generali. Supponendo un'operazione sincrona, il risultato sarà 200 OK o 409 CONFLICT a seconda dell'esito positivo o negativo. Nel caso di un CONFLITTO 409 , il processo deve essere riavviato poiché si è verificato un errore di blocco ottimistico nel nodo remoto (qualcuno ha modificato i dati durante la sincronizzazione). Gli aggiornamenti remoti vengono elaborati nell'ambito della propria transazione dell'applicazione.

Passaggio 4: aggiornamento locale

I dati estratti nel passaggio 2 vengono applicati localmente nell'ambito di una transazione dell'applicazione.

Sebbene quanto sopra non sia perfetto (ci sono diverse situazioni in cui locale e remoto possono avere problemi e avere dati di pull remoti da locale è probabilmente più efficiente di metterli in un grande PUT), dimostra come REST può essere usato durante un bi- processo di sincronizzazione direzionale.


6

Considererei un'operazione di sincronizzazione come una risorsa a cui è possibile accedere (GET) o creata (POST). Tenendo presente ciò, l'URL dell'API potrebbe essere:

/todo_services/abc123/synchronization

(Chiamandolo "sincronizzazione", non "sincronizzazione" per chiarire che non è un verbo)

Quindi fa:

POST /todo_services/abc123/synchronization

Per avviare una sincronizzazione. Poiché un'operazione di sincronizzazione è una risorsa, questa chiamata potrebbe potenzialmente restituire un ID che può quindi essere utilizzato per verificare lo stato dell'operazione:

GET /todo_services/abc123/synchronization?id=12345

3
Questa semplice risposta è LA risposta. Trasforma i tuoi verbi in sostantivi e
vai

5

Questo è un problema difficile Non credo che REST sia un livello appropriato per implementare la sincronizzazione. Una sincronizzazione affidabile dovrebbe essenzialmente essere una transazione distribuita. REST non è lo strumento per quel lavoro.

(Presupposto: per "sincronizzazione" si intende che una delle risorse può cambiare indipendentemente dall'altra in qualsiasi momento e si desidera la possibilità di riallinearle senza perdere gli aggiornamenti.)

Potresti prendere in considerazione la possibilità di rendere uno il "master" e l'altro lo "slave" in modo da poter bloccare con sicurezza lo slave periodicamente con i dati del master.

È inoltre possibile prendere in considerazione Microsoft Sync Framework se è assolutamente necessario supportare l'archiviazione dei dati in modo indipendente. Questo non funzionerebbe attraverso REST, ma dietro le quinte.


5
+1 per "problema difficile". La sincronizzazione bidirezionale è una di quelle cose che non ti rendi conto di quanto sia dura finché non sei nel profondo del fango.
Dan Ray,

2

Apache CouchDB è un database basato su REST, HTTP e JSON. Gli sviluppatori eseguono operazioni CRUD di base su HTTP. Fornisce inoltre un meccanismo di replica peer-to-peer che utilizza solo metodi HTTP.

Per fornire questa replica, CouchDB deve avere alcune convenzioni specifiche per CouchDB. Nessuno di questi è contrario al REST. Fornisce a ciascun documento (ovvero una risorsa REST all'interno di un database) un numero di revisione . Questo fa parte della rappresentazione JSON di quel documento, ma è anche nell'intestazione HTTP ETag. Ogni database ha anche un numero di sequenza che consente di tenere traccia delle modifiche al database nel suo insieme.

Per la risoluzione dei conflitti , notano semplicemente che un documento è in conflitto e mantengono le versioni in conflitto, lasciandolo agli sviluppatori che utilizzano il database per fornire un algoritmo di risoluzione dei conflitti.

Puoi utilizzare CouchDB come API REST, che ti darà la sincronizzazione immediata o dare un'occhiata a come fornisce la replica per fornire un punto di partenza per creare il tuo algoritmo.


Adoro CouchDB ed è il successore CouchBase + SyncGateway. +1
Leonid Usov

-1

È possibile risolvere il problema "I verbi sono cattivi" con una semplice ridenominazione: utilizzare "aggiornamenti" anziché "sincronizzazione".

Il processo di sincronizzazione sta effettivamente inviando un elenco di aggiornamenti locali effettuati dall'ultima sincronizzazione e ricevendo un elenco di aggiornamenti effettuati sul server nello stesso tempo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.