Seberapa baik Anda mewakili sinkronisasi dua arah dalam api REST?


23

Dengan asumsi sistem di mana ada Aplikasi Web dengan sumber daya, dan referensi ke aplikasi jarak jauh dengan sumber daya serupa lainnya, bagaimana Anda mewakili tindakan sinkronisasi dua arah yang menyinkronkan sumber daya 'lokal' dengan sumber daya 'jarak jauh'?

Contoh:

Saya memiliki API yang mewakili daftar todo.

DAPATKAN / POST / PUT / HAPUS / todos /, dll.

API itu dapat merujuk layanan TODO jarak jauh.

DAPATKAN / POST / PUT / HAPUS / todo_services /, dll.

Saya dapat memanipulasi todos dari layanan jarak jauh melalui API saya sebagai proxy melalui

DAPATKAN / POST / PUT / HAPUS / todo_services / abc123 /, dll.

Saya ingin kemampuan untuk melakukan sinkronisasi dua arah antara satu set lokal todos dan set remote TODOS.

Dengan cara rpc, orang bisa melakukannya

POST / todo_services / abc123 / sync /

Tetapi, dalam gagasan "kata kerja buruk", adakah cara yang lebih baik untuk mewakili tindakan ini?


4
Saya pikir desain API yang baik sangat tergantung pada pemahaman yang sangat konkret tentang apa yang Anda maksud dengan sinkronisasi. "Sinkronisasi" dari dua sumber data biasanya merupakan masalah yang sangat kompleks yang sangat mudah disederhanakan tetapi sangat sulit dipikirkan dalam semua implikasinya. Jadikan sinkronisasi "dua arah", dan tiba-tiba kesulitannya jauh lebih tinggi. Mulailah dengan memikirkan pertanyaan-pertanyaan sulit yang muncul.
Adam Crossland

Kanan - menganggap algoritme sinkronisasi dirancang dan berfungsi di API "level kode" - bagaimana cara mengekspos ini melalui REST. Sinkronisasi satu arah tampaknya jauh lebih mudah untuk diungkapkan: Saya GET /todo/1/dan POSTke /todo_services/abc123/ Tapi, cara 2 - Saya tidak mengambil dataset dan MENEMPATKANnya ke sumber daya, tindakan yang saya ambil sebenarnya menghasilkan potensi modifikasi dua sumber daya. Saya kira saya bisa jatuh kembali pada memiliki "melakukan sinkronisasi" menjadi sumber daya sendiri POST /todo_synchronizations/ {"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now"}
Edward M Smith

Kami masih memiliki masalah gerobak sebelum kuda. Maksud saya adalah Anda tidak dapat menganggap sinkronisasi hanya berfungsi dan mendesain API. Desain API akan didorong oleh berbagai kekhawatiran tentang bagaimana tepatnya algoritma sinkronisasi bekerja.
Adam Crossland

Itu berpotensi memaparkan hasil yang bermanfaat: GET /todo_synchronizations/1=>{"todos":["/todo/1/","/todo_services/abc123/1"],"schedule":"now","ran_at":"datetime","result":"success"}
Edward M Smith

2
Saya setuju dengan @Adam. Apakah Anda tahu cara menerapkan sinkronisasi? Bagaimana Anda menangani perubahan? Apakah Anda hanya memiliki dua set item yang ingin Anda rekonsiliasi atau apakah Anda memiliki log tindakan yang menyebabkan kedua set itu menyimpang sejak sinkronisasi terakhir? Alasan saya bertanya adalah sulit untuk mendeteksi menambahkan dan menghapus (terlepas dari REST). Jika Anda memiliki objek sisi server dan tidak memilikinya sisi klien, Anda harus bertanya pada diri sendiri, "Apakah klien menghapusnya atau apakah server membuatnya?" Hanya ketika Anda tahu persis bagaimana "sumber daya" berperilaku Anda dapat secara akurat menggambarkannya di REST.
Raymond Saltrelli

Jawaban:


17

Di mana dan apa sumber dayanya?

REST adalah semua tentang menangani sumber daya dengan cara yang tanpa kewarganegaraan dan dapat ditemukan. Itu tidak harus diimplementasikan melalui HTTP, juga tidak harus bergantung pada JSON atau XML, meskipun sangat disarankan bahwa format data hypermedia digunakan (lihat prinsip HATEOAS ) karena tautan dan id diinginkan.

Jadi, pertanyaannya menjadi: Bagaimana cara berpikir tentang sinkronisasi dalam hal sumber daya?

Apa itu sinkronisasi dua arah? **

Sinkronisasi dua arah adalah proses memperbarui sumber daya yang ada pada grafik node sehingga, pada akhir proses, semua node telah memperbarui sumber dayanya sesuai dengan aturan yang mengatur sumber daya tersebut. Biasanya, ini dipahami bahwa semua node akan memiliki versi terbaru dari sumber daya yang ada dalam grafik. Dalam kasus paling sederhana, grafik terdiri dari dua node: lokal dan jarak jauh. Lokal memulai sinkronisasi.

Jadi sumber daya utama yang perlu ditangani adalah log transaksi dan, oleh karena itu, proses sinkronisasi mungkin terlihat seperti ini untuk koleksi "item" di bawah HTTP:

Langkah 1 - Lokal mengambil log transaksi

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

Remote: 200 OK dengan isi yang berisi log transaksi yang berisi bidang-bidang yang mirip dengan ini

  • itemId - UUID untuk memberikan kunci primer bersama

  • updatedAt - cap waktu untuk memberikan titik terkoordinasi ketika data terakhir diperbarui (dengan asumsi bahwa riwayat revisi tidak diperlukan)

  • fingerprint- hash SHA1 dari isi data untuk perbandingan cepat jika updateAtbeberapa detik keluar

  • itemURI - URI lengkap ke item untuk memungkinkan pengambilan nanti

Langkah 2 - Lokal membandingkan log transaksi jarak jauh dengan miliknya

Ini adalah penerapan aturan bisnis tentang cara menyinkronkan. Biasanya, itemIdakan mengidentifikasi sumber daya lokal, lalu membandingkan sidik jari. Jika ada perbedaan maka perbandingan updatedAtdibuat. Jika ini terlalu dekat untuk dipanggil maka keputusan harus dibuat untuk menarik berdasarkan simpul lain (mungkin lebih penting), atau untuk mendorong ke simpul lain (simpul ini lebih penting). Jika sumber daya jarak jauh tidak ada secara lokal maka entri push dibuat (ini berisi data aktual untuk dimasukkan / diperbarui). Sumber daya lokal apa pun yang tidak ada dalam log transaksi jarak jauh diasumsikan tidak berubah.

Permintaan tarikan dibuat terhadap node jarak jauh sehingga data ada secara lokal menggunakan itemURI. Mereka tidak diterapkan secara lokal sampai nanti.

Langkah 3 - Dorong log transaksi sinkronisasi lokal ke jarak jauh

Lokal: PUT /remotehost/items/transactions dengan badan yang berisi log transaksi sinkronisasi lokal.

Node jarak jauh mungkin memproses ini secara sinkron (jika kecil dan cepat) atau asinkron (pikirkan 202 DITERIMA ) jika nampaknya akan menimbulkan banyak overhead. Dengan asumsi operasi sinkron, maka hasilnya akan menjadi 200 OK atau 409 CONFLICT tergantung pada keberhasilan atau kegagalan. Dalam kasus 409 CONFLICT , maka proses tersebut harus dimulai lagi karena ada kegagalan penguncian yang optimis di node jauh (seseorang mengubah data selama sinkronisasi). Pembaruan jarak jauh diproses berdasarkan transaksi aplikasi mereka sendiri.

Langkah 4 - Perbarui secara lokal

Data yang ditarik di Langkah 2 diterapkan secara lokal di bawah transaksi aplikasi.

Walaupun hal di atas tidak sempurna (ada beberapa situasi di mana lokal dan jarak jauh mungkin mendapat masalah dan memiliki data tarikan jarak jauh dari lokal mungkin lebih efisien daripada menjejalkannya ke dalam PUT besar) itu menunjukkan bagaimana REST dapat digunakan selama dua proses sinkronisasi directional.


6

Saya akan mempertimbangkan operasi sinkronisasi sebagai sumber daya yang dapat diakses (GET) atau dibuat (POST). Dengan mengingat hal itu, URL API dapat:

/todo_services/abc123/synchronization

(Menyebutnya "sinkronisasi", bukan "sinkronisasi" untuk membuatnya jelas itu bukan kata kerja)

Lalu lakukan:

POST /todo_services/abc123/synchronization

Untuk memulai sinkronisasi. Karena operasi sinkronisasi adalah sumber daya, panggilan ini berpotensi mengembalikan ID yang kemudian dapat digunakan untuk memeriksa status operasi:

GET /todo_services/abc123/synchronization?id=12345

3
Jawaban sederhana ini adalah jawabannya. Ubah kata kerja Anda menjadi kata benda dan lanjutkan ...
HDave

5

Ini masalah yang sulit. Saya tidak percaya REST adalah level yang tepat untuk mengimplementasikan sinkronisasi. Sinkronisasi yang kuat pada dasarnya perlu menjadi transaksi terdistribusi. REST bukan alat untuk pekerjaan itu.

(Asumsi: dengan "menyinkronkan" Anda menyiratkan bahwa salah satu sumber daya dapat berubah secara independen dari yang lain setiap saat, dan Anda ingin kemampuan untuk menyelaraskannya tanpa kehilangan pembaruan.)

Anda mungkin ingin mempertimbangkan untuk menjadikan salah satu "master" dan yang lainnya "budak" sehingga Anda dapat dengan percaya diri mengalahkan budak secara berkala dengan data dari master.

Anda juga mungkin ingin mempertimbangkan Kerangka Kerja Microsoft Sync jika Anda benar-benar perlu mendukung penyimpanan data yang berubah secara independen. Ini tidak akan berhasil melalui REST, tetapi di belakang layar.


5
+1 untuk "masalah sulit". Sinkronisasi dua arah adalah salah satu hal yang tidak Anda sadari betapa sulitnya sampai Anda tenggelam dalam lumpur.
Dan Ray

2

Apache CouchDB adalah database yang didasarkan pada REST, HTTP, dan JSON. Pengembang melakukan operasi CRUD dasar melalui HTTP. Ini juga menyediakan mekanisme replikasi yang peer-to-peer hanya menggunakan metode HTTP.

Untuk memberikan replikasi ini, CouchDB perlu memiliki beberapa konvensi khusus CouchDB. Tidak ada yang menentang REST. Ini memberikan setiap dokumen (yang merupakan sumber daya REST dalam database) dengan nomor revisi . Ini adalah bagian dari representasi JSON dari dokumen itu, tetapi juga di header HTTP ETag. Setiap basis data juga memiliki nomor urut yang memungkinkan untuk melacak perubahan pada basis data secara keseluruhan.

Untuk resolusi konflik , mereka hanya mencatat bahwa suatu dokumen bertentangan dan mempertahankan versi yang bertentangan, menyerahkannya kepada pengembang menggunakan database untuk menyediakan algoritma resolusi konflik.

Anda bisa menggunakan CouchDB sebagai REST API Anda, yang akan memberi Anda sinkronisasi di luar kotak, atau lihat bagaimana itu menyediakan replikasi untuk memberikan titik awal untuk membuat algoritma Anda sendiri.


Saya suka CouchDB, dan itu adalah penerus CouchBase + SyncGateway. +1
Leonid Usov

-1

Anda dapat menyelesaikan masalah "kata kerja buruk" dengan penggantian nama sederhana - gunakan "pembaruan" alih-alih "sinkronkan".

Proses sinkronisasi sebenarnya mengirimkan daftar pembaruan lokal yang dibuat sejak sinkronisasi terakhir, dan menerima daftar pembaruan yang dibuat pada server dalam waktu yang bersamaan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.