Bagaimana saya harus merancang sumber daya daftar yang dipesan dalam layanan yang tenang?

11

Saya mengalami masalah yang sama berulang-ulang dan saya belum menemukan solusi yang saya rasa optimal.

Katakan dalam sebuah aplikasi, Anda memiliki daftar yang dipesan dan Anda membiarkan pengguna mengubah urutan itu dengan drag and drop atau apalah. Anda ingin perubahan agar tetap ada. Bagaimana Anda membuat model itu?

Bagaimana saya harus merancang layanan yang tenang dari sumber daya daftar yang dipesan?

Secara khusus, bagaimana saya harus mendesain listdan itemmodel sumber daya yang tenang? Desain paling umum yang pernah saya lihat adalah itementitas yang memiliki orderatau positionproperti. Pendekatan lain yang saya dengar adalah daftar item yang terhubung dua kali lipat.

Apa pendekatan yang tidak menulis terlalu banyak ke basis data dan umumnya cepat untuk memperbarui dan membaca untuk klien? Bagaimana seharusnya titik akhir terpapar?

Rico Kahler
sumber
Karena penasaran, mengapa penting untuk mengembalikan daftar yang dipesan secara khusus?
Adam Wells
Yah saya kira saya tidak secara khusus mencari untuk mengembalikan sumber daya daftar yang dipesan tetapi hanya bertahan urutan / posisi sumber daya yang dapat menjadi bagian dari sumber daya daftar yang sebenarnya atau hanya secara implisit bagian dari daftar. Saya ingin mengatakan biarkan pengguna mengubah urutan todo dalam daftar todos. Tetapi tidak peduli apa masih ada daftar di mana urutan itu penting. Apa yang tidak dapat saya temukan adalah cara yang baik untuk mendesain ini
Rico Kahler

Jawaban:

14

Mewakili daftar yang dipesan adalah salah satu masalah sulit dengan database relasional. Menambahkan properti posisi ke hubungan daftar-keanggotaan adalah cara paling umum untuk melakukan ini, karena Anda dapat dengan mudah mengambil daftar yang diurutkan dengan menambahkan ORDER BY positionke permintaan SQL Anda, dan karena Anda dapat dengan mudah memasukkan item di tengah daftar dengan rata-rata nilai anggota daftar sebelumnya dan selanjutnya, dengan asumsi posisi adalah float daripada integer.

Menggunakan daftar yang ditautkan dua kali harus dihindari, karena mudah untuk secara tidak sengaja membuat tautan tidak konsisten, dan berakhir dengan grafik atau pohon siklik sebagai gantinya.

Namun, API tenang tidak menderita dari pembatasan database relasional. Anda bisa melakukan sesuatu yang terasa alami, daripada menggunakan peretasan seperti properti posisi.

Jika Anda hanya memiliki beberapa ratus elemen dalam daftar, cukup transfer seluruh daftar dalam permintaan. Dengan asumsi kami ingin menyusun ulang di [1, 2, 3, 4]mana anggota daftar adalah ID, kami bisa

POST /url/of/the/list
Content-type: application/json
...

[1, 2, 4, 3]

Backend kemudian dapat menerjemahkan ini ke teknologi database apa pun yang Anda gunakan, tetapi pengguna API tidak harus mempertimbangkan detail ini.

Jika daftar besar dan item biasanya akan diminta secara individual, Anda dapat mengizinkan indeks di url:

GET /page/7

Jika Anda menyukai HATEOAS, responsnya dapat mencakup tautan prev / next untuk menyederhanakan navigasi, jika sumber daya biasanya dikonsumsi seperti itu. Namun, ini tidak perlu menyiratkan bahwa database Anda juga berisi daftar yang ditautkan dua kali lipat ini.

Jika daftar ini sangat besar, Anda mungkin ingin mengekspos ArrayListoperasi seperti-seperti insertatau push/ append. Saya bisa membayangkan panggilan seperti itu

POST /url/of/the/list?at=1357;mode=insert
...

description of the item to insert

Jika pemesanan ulang adalah kasus penggunaan umum dan pemesanan ulang harus dilakukan segera, maka Anda dapat menawarkan titik akhir yang sesuai di API Anda:

POST /url/of/the/list/reorder-item?from=783;to=1357

Jika daftar yang dipesan ulang harus dilakukan secara eksplisit, akan lebih mudah untuk mentransfer pesanan baru sebagai dokumen JSON, lihat di atas.

Sekarang tidak sepenuhnya benar bahwa Anda dapat melihat API Anda sepenuhnya terpisah dari teknologi basis data yang Anda gunakan. Namun, yang terbaik adalah menjaga API eksternal sebebas mungkin dari detail implementasi. Jika pemesanan ulang menyentuh sekitar 30 baris hanya untuk memperbarui kolom pesanan integer, itu bukan masalah besar. Lakukan saja hal yang paling sederhana dan perbarui seluruh daftar. Jika skala Anda mengharuskan penggunaan basis data Anda menjadi lebih canggih, lebih baik menangkap kecanggihan ini di backend, di mana lebih mudah untuk mempertahankan konsistensi.

amon
sumber
1
Perhatikan bahwa pendekatan "ganti seluruh daftar" dapat menjadi masalah jika ada banyak klien yang melakukan perubahan. Jika Anda tidak melakukan tindakan pencegahan apa pun, Anda mungkin akan menimpa perubahan orang lain ("terakhir menulis kemenangan").
oefe
Operasi seperti daftar seharusnya tidak memiliki masalah ini, asalkan parameter (pada, dari, ke) id, bukan daftar indeks
oefe
2

Saya pikir kelayakan pendekatan yang berbeda sangat bergantung pada basis data yang digunakan.

Pendekatan ini menyarankan untuk memindahkan item dalam pemesanan:

POST / url / of / the / list / reorder-item? Dari = 783; ke = 1357

Itu dapat dikenakan kondisi lomba kecuali Anda memiliki transaksionalitas SERIALIZABLE. Level default READ_COMMITTED di sebagian besar DB tidak akan menghilangkan kondisi balapan!

Saya benar-benar berpikir bahwa dalam kebanyakan kasus - selama daftar ini relatif kecil - maka pendekatan daftar-ganti memiliki lebih sedikit masalah dengan kondisi balapan dan tidak dapat merusak data. Jika set item telah berubah sejak klien mengajukan permintaan, Anda dapat mengembalikan 409 (Konflik).

Itu menderita terakhir-menulis-menang, tapi itu benar-benar api APAPUN. Apa pun API yang Anda laksanakan, klien lain mungkin telah memperbarui hal itu saat Anda melihat halaman.

Charles Capps
sumber