Pola desain apa yang terbukti ada untuk operasi batch pada sumber daya dalam layanan web gaya REST?
Saya mencoba untuk menjadi keseimbangan antara cita-cita dan kenyataan dalam hal kinerja dan stabilitas. Kami memiliki API sekarang di mana semua operasi diambil dari sumber daya daftar (yaitu: GET / pengguna) atau dalam satu contoh (PUT / pengguna / 1, DELETE / pengguna / 22, dll).
Ada beberapa kasus di mana Anda ingin memperbarui satu bidang dari seluruh rangkaian objek. Tampaknya sangat boros untuk mengirim seluruh representasi untuk setiap objek bolak-balik untuk memperbarui satu bidang.
Dalam API gaya RPC, Anda dapat memiliki metode:
/mail.do?method=markAsRead&messageIds=1,2,3,4... etc.
Apa persamaan REST di sini? Atau tidak masalah untuk berkompromi sesekali. Apakah itu merusak desain untuk menambah beberapa operasi tertentu di mana itu benar-benar meningkatkan kinerja, dll? Klien dalam semua kasus sekarang adalah Web Browser (aplikasi javascript di sisi klien).
sumber
PATCH
- tidak perlu kreativitas dalam hal ini.Tidak sama sekali - saya pikir REST yang setara adalah (atau setidaknya satu solusi) hampir persis seperti itu - antarmuka khusus yang dirancang mengakomodasi operasi yang diperlukan oleh klien.
Saya teringat akan pola yang disebutkan dalam buku Crane dan Pascarello, Ajax in Action (buku yang luar biasa, sangat direkomendasikan) di mana mereka menggambarkan penerapan CommandQueue jenis objek yang tugasnya adalah mengantri permintaan ke dalam kumpulan dan kemudian kirimkan ke server secara berkala.
Objek, jika saya ingat dengan benar, pada dasarnya hanya memegang array "perintah" - misalnya, untuk memperluas contoh Anda, masing-masing catatan berisi perintah "markAsRead", "messageId" dan mungkin referensi ke callback / handler fungsi - dan kemudian sesuai dengan beberapa jadwal, atau pada beberapa tindakan pengguna, objek perintah akan diserialisasi dan diposting ke server, dan klien akan menangani pasca pemrosesan.
Saya tidak kebetulan memiliki detailnya, tetapi sepertinya antrian perintah semacam ini akan menjadi salah satu cara untuk menangani masalah Anda; itu akan mengurangi chattiness keseluruhan secara substansial, dan itu akan abstrak antarmuka sisi server dengan cara Anda mungkin menemukan lebih fleksibel di jalan.
Perbarui : Aha! Saya telah menemukan potongan dari buku online itu, lengkap dengan contoh kode (meskipun saya masih menyarankan mengambil buku yang sebenarnya!). Lihat di sini , dimulai dengan bagian 5.5.3:
Berikut adalah dua fungsi terkait - satu bertanggung jawab untuk menambahkan perintah ke antrian (
addCommand
), dan satu bertanggung jawab untuk membuat serial dan kemudian mengirimkannya ke server (fireRequest
):Itu seharusnya membuat Anda pergi. Semoga berhasil!
sumber
Sementara saya pikir @Alex berada di jalur yang benar, secara konseptual saya pikir itu harus menjadi kebalikan dari apa yang disarankan.
URL berlaku "sumber daya yang kami targetkan" karenanya:
berarti mendapatkan catatan dari email dengan id 1 dan
berarti menambal catatan surat dengan id 1. Pertanyaannya adalah "filter", memfilter data yang dikembalikan dari URL.
Jadi di sini kami meminta semua surat yang sudah ditandai sebagai sudah dibaca. Jadi untuk [PATCH] ke jalur ini akan mengatakan "tambalan catatan sudah ditandai sebagai benar" ... yang bukan apa yang kita coba capai.
Jadi metode batch, mengikuti pemikiran ini harus:
tentu saja saya tidak mengatakan ini benar REST (yang tidak mengizinkan manipulasi catatan batch), melainkan mengikuti logika yang sudah ada dan digunakan oleh REST.
sumber
[GET]
format yang harus dilakukan[PATCH] mail?markAsRead=true data: [{"id": 1}, {"id": 2}, {"id": 3}]
(atau bahkan adildata: {"ids": [1,2,3]}
)? Manfaat lain dari pendekatan alternatif ini adalah Anda tidak akan mengalami kesalahan "414 URI Request terlalu lama" jika Anda memperbarui ratusan / ribuan sumber daya dalam koleksi.Bahasa Anda, " Sepertinya sangat boros ...", bagi saya menunjukkan upaya optimasi prematur. Kecuali dapat ditunjukkan bahwa mengirimkan seluruh representasi objek adalah hit kinerja utama (kita berbicara tidak dapat diterima pengguna sebagai> 150 ms) maka tidak ada gunanya mencoba membuat perilaku API non-standar yang baru. Ingat, semakin sederhana API, semakin mudah digunakan.
Untuk menghapus, kirim yang berikut karena server tidak perlu tahu apa-apa tentang keadaan objek sebelum penghapusan terjadi.
Pikiran berikutnya adalah bahwa jika suatu aplikasi mengalami masalah kinerja mengenai pembaruan massal objek maka pertimbangan memecah setiap objek menjadi beberapa objek harus diberikan. Dengan begitu muatan JSON adalah sebagian kecil dari ukuran.
Sebagai contoh ketika mengirim respons untuk memperbarui status "baca" dan "diarsipkan" dari dua email terpisah, Anda harus mengirim yang berikut:
Saya akan membagi komponen email yang dapat diubah (baca, diarsipkan, penting, label) menjadi objek terpisah karena yang lain (agar, dari, subjek, teks) tidak akan pernah diperbarui.
Pendekatan lain yang harus diambil adalah memanfaatkan penggunaan PATCH. Untuk secara eksplisit menunjukkan properti yang ingin Anda perbarui dan yang lainnya harus diabaikan.
Orang-orang menyatakan bahwa PATCH harus diimplementasikan dengan memberikan berbagai perubahan yang mengandung: action (CRUD), path (URL), dan perubahan nilai. Ini dapat dianggap sebagai implementasi standar tetapi jika Anda melihat keseluruhan REST API, ini adalah non-intuitif sekali saja. Juga, implementasi di atas adalah bagaimana GitHub telah mengimplementasikan PATCH .
Singkatnya, dimungkinkan untuk mematuhi prinsip RESTful dengan aksi batch dan masih memiliki kinerja yang dapat diterima.
sumber
Google drive API memiliki sistem yang sangat menarik untuk menyelesaikan masalah ini ( lihat di sini ).
Apa yang mereka lakukan pada dasarnya adalah mengelompokkan permintaan yang berbeda dalam satu
Content-Type: multipart/mixed
permintaan, dengan masing-masing permintaan lengkap dipisahkan oleh beberapa pembatas yang ditentukan. Header dan parameter kueri dari permintaan batch diwarisi untuk permintaan individu (yaituAuthorization: Bearer some_token
) kecuali mereka ditimpa dalam permintaan individu.Contoh : (diambil dari dokumen mereka )
Permintaan:
Tanggapan:
sumber
Saya akan tergoda dalam operasi seperti yang ada dalam contoh Anda untuk menulis parser rentang.
Tidak sulit untuk membuat parser yang bisa membaca "messageIds = 1-3,7-9,11,12-15". Ini tentu akan meningkatkan efisiensi untuk operasi selimut yang mencakup semua pesan dan lebih terukur.
sumber
Pos yang bagus. Saya telah mencari solusi selama beberapa hari. Saya datang dengan solusi menggunakan melewatkan string kueri dengan banyak ID yang dipisahkan oleh koma, seperti:
... lalu meneruskannya ke
WHERE IN
klausa di SQL saya. Ini bekerja dengan baik, tetapi pikirkan apa yang orang lain pikirkan tentang pendekatan ini.sumber
DELETE /books/delete?id=1,2,3
ketika buku # 3 tidak ada -WHERE IN
kehendak diam-diam mengabaikan catatan, sedangkan saya biasanya berharapDELETE /books/delete?id=3
untuk 404 jika 3 tidak ada.Dari sudut pandang saya, saya pikir Facebook memiliki implementasi terbaik.
Permintaan HTTP tunggal dibuat dengan parameter batch dan satu untuk token.
Dalam batch json dikirim. yang berisi koleksi "permintaan". Setiap permintaan memiliki properti metode (get / post / put / delete / etc ...), dan properti relative_url (uri dari titik akhir), selain itu metode post dan put memungkinkan properti "tubuh" tempat bidang diperbarui terkirim .
info lebih lanjut di: Facebook batch API
sumber