Hapus beberapa catatan menggunakan REST

100

Apa cara REST-ful untuk menghapus beberapa item?

Kasus penggunaan saya adalah saya memiliki Koleksi Tulang Belakang di mana saya harus dapat menghapus beberapa item sekaligus. Opsinya sepertinya:

  1. Kirim permintaan DELETE untuk setiap record (yang sepertinya ide buruk jika ada banyak item yang berpotensi);
  2. Kirim HAPUS di mana ID yang akan dihapus dirangkai di URL (yaitu, "/ records / 1; 2; 3");
  3. Dengan cara non-REST, kirim objek JSON khusus yang berisi ID yang ditandai untuk dihapus.

Semua opsi kurang dari ideal.

Ini tampak seperti area abu-abu dari konvensi REST.

Donald Taylor
sumber
3
Kemungkinan duplikat cara
Istirahat

Jawaban:

93
  1. Merupakan pilihan RESTful yang layak, tetapi jelas memiliki keterbatasan yang telah Anda jelaskan.
  2. Jangan lakukan ini. Ini akan ditafsirkan oleh perantara sebagai arti "HAPUS sumber daya (tunggal) di /records/1;2;3" - Jadi tanggapan 2xx untuk ini dapat menyebabkan mereka membersihkan cache mereka /records/1;2;3; tidak membersihkan /records/1, /records/2atau /records/3; proxy respons 410 untuk /records/1;2;3, atau hal-hal lain yang tidak masuk akal dari sudut pandang Anda.
  3. Pilihan ini adalah yang terbaik, dan dapat dilakukan dengan tenang. Jika Anda membuat API dan ingin mengizinkan perubahan massal pada sumber daya, Anda dapat menggunakan REST untuk melakukannya, tetapi cara persisnya tidak langsung terlihat oleh banyak orang. Salah satu metodenya adalah membuat sumber daya 'permintaan perubahan' (misalnya dengan melakukan POSTING pada badan seperti records=[1,2,3]to /delete-requests) dan mengumpulkan sumber daya yang dibuat (ditentukan oleh Locationheader respons) untuk mengetahui apakah permintaan Anda telah diterima, ditolak, sedang berlangsung atau telah selesai. Ini berguna untuk operasi yang berjalan lama. Cara lain adalah mengirim PATCHpermintaan ke sumber daya daftar ,/records, yang isinya berisi daftar resource dan tindakan yang harus dilakukan pada resource tersebut (dalam format apa pun yang ingin Anda dukung). Ini berguna untuk operasi cepat di mana kode respons untuk permintaan dapat menunjukkan hasil operasi.

Semuanya dapat dicapai dengan tetap berada dalam batasan REST, dan biasanya jawabannya adalah menjadikan "masalah" menjadi sumber daya, dan memberinya URL.
Jadi, operasi batch, seperti hapus di sini, atau POST beberapa item ke daftar, atau lakukan pengeditan yang sama ke sejumlah resource, semuanya dapat ditangani dengan membuat daftar "operasi batch" dan melakukan POST operasi baru Anda ke sana.

Jangan lupa, REST bukanlah satu-satunya cara untuk menyelesaikan masalah apa pun. "REST" hanyalah gaya arsitektur dan Anda tidak harus mematuhinya (tetapi Anda akan kehilangan manfaat tertentu dari internet jika tidak melakukannya). Saya sarankan Anda melihat daftar arsitektur HTTP API ini dan pilih yang cocok untuk Anda. Cukup buat diri Anda sadar akan kerugian yang Anda alami jika memilih arsitektur lain, dan buat keputusan yang tepat berdasarkan kasus penggunaan Anda.

Ada beberapa jawaban buruk untuk pertanyaan ini tentang Pola untuk menangani operasi batch di layanan web REST? yang memiliki terlalu banyak suara positif, tetapi harus dibaca juga.

Nicholas Shanks
sumber
2
Bukan server Anda yang perlu Anda khawatirkan, melainkan perantara, CDN, proxy caching, dll. Internet adalah sistem berlapis. Itulah alasannya bekerja dengan sangat baik. Roy menentukan aspek mana dari sistem yang diperlukan untuk keberhasilannya, dan menamakannya REST. Jika Anda mengeluarkan DELETEpermintaan, apa pun yang ada di antara pemohon dan server akan menganggap satu sumber daya, di URL yang ditentukan, sedang dihapus. String kueri adalah bagian buram dari URL ke perangkat ini, jadi tidak peduli bagaimana Anda menentukan API Anda, mereka tidak mengetahui rahasia pengetahuan ini sehingga tidak dapat berperilaku berbeda.
Nicholas Shanks
3
/ records / 1; 2; 3 tidak akan berfungsi jika Anda memiliki banyak resource untuk dihapus karena batasan panjang URI
dukethrash
3
Perhatikan bahwa jika mempertimbangkan DELETE dan badan yang menentukan sumber daya yang akan dibersihkan, beberapa perantara mungkin tidak meneruskan badan tersebut. Selain itu, beberapa klien HTTP tidak dapat menambahkan isi ke DELETE. Lihat stackoverflow.com/questions/299628/…
Luke Puplett
3
@ LukePuplett Saya hanya akan menyatakan bahwa melewatkan tubuh permintaan dengan DELETEpermintaan dilarang. Jangan lakukan itu. Jika Anda melakukannya, saya akan memakan anak-anak Anda. Nyam nyam nyam.
Nicholas Shanks
3
Masalah dengan argumen untuk # 3 adalah bahwa hal itu membawa hukuman yang sama dengan argumen balasan terhadap # 2. Membuat sumber daya untuk dihapus bukanlah sesuatu yang proksi upstream akan tahu bagaimana menanganinya - argumen balasan yang sama yang dimunculkan terhadap pendekatan # 2.
LB2
16

Jika GET /records?filteringCriteriamengembalikan array dari semua catatan yang cocok dengan kriteria, maka DELETE /records?filteringCriteriabisa menghapus semua catatan tersebut.

Dalam hal ini jawaban atas pertanyaan Anda adalah DELETE /records?id=1&id=2&id=3.

Martin Ždila
sumber
1
Saya juga sampai pada kesimpulan ini: balik saja kata kerjanya ke apa yang ingin Anda lakukan. Saya tidak mengerti bagaimana GET tidak berarti DELETE.
Luke Puplett
9
GET /records?id=1&id=2&id=3tidak tidak berarti “mendapatkan tiga catatan dengan ID 1, 2 & 3”, itu berarti “mendapatkan sumber daya tunggal dengan URL path / catatan? id = 1 & id = 2 & id = 3” yang mungkin menjadi gambaran lobak, teks biasa dokumen yang berisi nomor "42" dalam bahasa Cina, atau mungkin tidak ada.
Nicholas Shanks
Pertimbangkan hal berikut: dua permintaan berurutan untuk /records?id=1dan /records?id=2dikirim, dan tanggapan mereka disimpan dalam cache oleh beberapa perantara (misalnya browser atau ISP Anda). Jika internet tahu apa yang dimaksud aplikasi Anda dengan ini, maka masuk akal bahwa permintaan /records?id=1&id=2dapat dikembalikan oleh cache hanya dengan menggabungkan (entah bagaimana) dua hasil yang sudah dimilikinya, tanpa harus bertanya kepada server asal. Tapi ini tidak mungkin. /records?id=1&id=2mungkin tidak valid (hanya 1 ID diperbolehkan per permintaan) atau mungkin mengembalikan sesuatu yang sama sekali berbeda (lobak).
Nicholas Shanks
Ini adalah masalah cache sumber daya dasar. Jika DBA saya mengubah status secara langsung, maka cache sekarang tidak sinkron. Anda memberikan contoh 410 yang dikembalikan oleh perantara, tetapi 410 untuk penghapusan permanen, setelah HAPUS cache mungkin mengosongkan slotnya untuk URL itu, tetapi tidak akan mengirim 410 atau 404, karena tidak tahu apakah DBA tidak hanya segera mengembalikan sumber daya ke asalnya.
Luke Puplett
4
@NicholasShanks Saya sangat tidak setuju. Jika hasilnya di-cache, itu adalah kesalahan server. Dan jika Anda berbicara tentang desain API, semoga Anda yang menulis kode untuk server. Apakah Anda menggunakan id[]=1&id[]=2atau id=1&id=2dalam string kueri untuk mewakili larik nilai, string kueri itu tidak mewakili hal itu. Dan saya pikir itu sangat umum & praktik yang baik untuk memiliki string kueri yang mewakili filter. Selain itu, jika Anda mengizinkan penghapusan dan pembaruan, jangan cache GETpermintaan. Jika Anda melakukannya, klien akan memiliki status basi.
Joseph Nields
10

Saya pikir Mozilla Storage Service SyncStorage API v1.5 adalah cara yang baik untuk menghapus banyak catatan menggunakan REST.

Menghapus seluruh koleksi.

DELETE https://<endpoint-url>/storage/<collection>

Menghapus beberapa BSO dari koleksi dengan satu permintaan.

DELETE https://<endpoint-url>/storage/<collection>?ids=<ids>

ids : menghapus BSO dari koleksi yang idnya ada dalam daftar yang dipisahkan koma. Maksimal 100 id dapat disediakan.

Menghapus BSO di lokasi tertentu.

DELETE https://<endpoint-url>/storage/<collection>/<id>

http://moz-services-docs.readthedocs.io/en/latest/storage/apis-1.5.html#api-instructions

bootsoon
sumber
Sepertinya ini solusi yang bagus. Saya kira jika mozilla menganggapnya benar maka itu pasti? Satu-satunya pertanyaan adalah penanganan kesalahan. Misalkan mereka lolos? Ids = 1,2,3 dan id 3 tidak ada apakah Anda menghapus 1 dan 2 lalu merespon dengan 200 karena pemohon ingin 3 hilang dan tidak ada jadi tidak masalah? atau bagaimana jika mereka diizinkan untuk menghapus 1 tetapi bukan 2 ... apakah Anda tidak menghapus apa pun dan merespons dengan kesalahan atau apakah Anda menghapus apa yang Anda bisa dan membiarkan yang lain ...
tempcke
Saya biasanya akan mengembalikan respons yang berhasil karena keadaan akhirnya sama. Ini juga menyederhanakan logika pada klien karena mereka tidak lagi harus menangani status kesalahan itu. Sedangkan untuk kasus otorisasi, saya hanya akan menggagalkan seluruh permintaan ... tetapi sebenarnya itu tergantung pada kasus penggunaan Anda.
Nathan Phetteplace
3

Ini tampak seperti area abu-abu dari konvensi REST.

Ya, sejauh ini saya hanya menemukan satu panduan desain REST API yang menyebutkan operasi batch (seperti penghapusan batch): panduan desain google api .

Panduan ini menyebutkan pembuatan metode "kustom" yang dapat dikaitkan melalui sumber daya dengan menggunakan titik dua, misalnya https://service.name/v1/some/resource/name:customVerb, juga secara eksplisit menyebutkan operasi batch sebagai kasus penggunaan:

Metode kustom dapat dikaitkan dengan sumber daya, koleksi, atau layanan. Ini mungkin mengambil permintaan sewenang-wenang dan mengembalikan tanggapan sewenang-wenang, dan juga mendukung permintaan dan tanggapan streaming. [...] Metode kustom harus menggunakan kata kerja HTTP POST karena ia memiliki semantik paling fleksibel [...] Untuk metode kinerja kritis, mungkin berguna untuk menyediakan metode batch kustom untuk mengurangi overhead per permintaan .

Jadi Anda bisa melakukan yang berikut ini sesuai dengan panduan api google:

POST /api/path/to/your/collection:batchDelete

... untuk menghapus sekumpulan item sumber daya koleksi Anda.

B12Pemanggang
sumber
Apakah solusi yang layak dimana daftar item dikomunikasikan melalui array berformat JSON?
Daniele
ya tentu. Anda dapat POST payload di mana id dikirim melalui array json.
B12Toaster
Sangat menarik bahwa panduan Google API mengatakan If the HTTP verb used for the custom method does not accept an HTTP request body (GET, DELETE), the HTTP configuration of such method must not use the body clause at all,di bab Metode Kustom. Tetapi GET accounts.locations.batchGetapi adalah metode GET dengan tubuh. Itu aneh. developers.google.com/my-business/reference/rest/v4/…
鄭元傑
@ 鄭元傑 setuju, terlihat agak aneh pada pandangan pertama tetapi jika Anda melihat lebih dekat itu sebenarnya adalah POSTmetode http yang digunakan dan hanya metode kustom yang dinamai batchGet. Saya kira google melakukannya untuk (a) berpegang teguh pada aturan mereka bahwa semua metode kustom harus POST(lihat jawaban saya) dan (b) untuk memudahkan orang untuk meletakkan "filter" di tubuh sehingga Anda tidak perlu escape atau encode filter seperti string kueri. sisi negatifnya, tentu saja, ini tidak benar-benar dapat disimpan dalam cache lagi ...
B12Toaster
https://service.name/v1/some/resource/name:customVerbtidak RESTful menurut definisi.
deamon
2

Saya telah mengizinkan penggantian grosir suatu koleksi, misalnya di PUT ~/people/123/shoesmana tubuh adalah representasi seluruh koleksi.

Ini berfungsi untuk koleksi anak kecil dari item di mana klien ingin meninjau item dan memangkas beberapa dan menambahkan beberapa lainnya dan kemudian memperbarui server. Mereka dapat MENEMPATKAN koleksi kosong untuk menghapus semua.

Ini berarti GET ~/people/123/shoes/9akan tetap ada dalam cache meskipun PUT menghapusnya, tetapi itu hanya masalah cache dan akan menjadi masalah jika beberapa orang lain menghapus sepatu tersebut.

API data / sistem saya selalu menggunakan ETag sebagai lawan dari waktu kedaluwarsa sehingga server terkena setiap permintaan, dan saya memerlukan header versi / konkurensi yang benar untuk mengubah data. Untuk API yang hanya-baca dan tampilan / laporan selaras, saya menggunakan waktu kedaluwarsa untuk mengurangi klik pada asal, misalnya papan peringkat bisa berlangsung selama 10 menit.

Untuk koleksi yang jauh lebih besar, seperti ~/people, saya cenderung tidak memerlukan banyak penghapusan, kasus penggunaan cenderung tidak muncul secara alami dan DELETE tunggal berfungsi dengan baik.

Di masa depan, dan dari pengalaman dengan membangun REST API dan mencapai masalah dan persyaratan yang sama, seperti audit, saya cenderung hanya menggunakan kata kerja GET dan POST dan desain di sekitar peristiwa, misalnya POST peristiwa perubahan alamat, meskipun saya curiga bahwa akan datang dengan masalah tersendiri :)

Saya juga akan mengizinkan pengembang front-end untuk membangun API mereka sendiri yang menggunakan API back-end yang lebih ketat karena seringkali ada alasan sisi klien yang valid dan praktis mengapa mereka tidak menyukai desain REST API "Fielding fanatik" yang ketat, dan untuk produktivitas dan alasan pelapisan cache.

Luke Puplett
sumber
Saya menyukai jawaban ini sampai saya membaca kalimat terakhir :) Saya belum pernah melihat kasus penggunaan di mana menerapkan REST ketat memiliki efek yang merugikan. Tentu itu dapat membuat lebih banyak kode untuk ditulis di kedua ujungnya, tetapi Anda berakhir dengan sistem yang lebih aman, lebih bersih, dan kurang terhubung.
Nicholas Shanks
Ha ha. Ini benar-benar menjadi sebuah pola! Backend untuk front-end disebut radar teknologi ThoughtWorks. Ini juga memungkinkan lebih banyak logika aplikasi untuk ditulis yang akan merepotkan dalam katakanlah, JavaScript, dan jelas dapat diperbarui tanpa klien jadi katakanlah pembaruan, untuk aplikasi iOS.
Luke Puplett
Membaca sekilas empat hit pertama dari Google, tampaknya teknik BFF ini hanya dapat bekerja bila klien berada di bawah kendali Anda . Pengembang klien mengembangkan API yang mereka inginkan, memetakan panggilan ke API layanan mikro yang merupakan back end sebenarnya. Dalam diagram ini: samnewman.io/patterns/architectural/bff/#bff Saya akan menempatkan baris "Perimeter" di bawah kotak BFF - setiap kotak hanyalah bagian dari klien. Ia bahkan bisa hidup di luar pusat data yang menampung layanan mikro. Saya juga tidak melihat bagaimana REST tidak berlaku untuk kedua antarmuka (klien / BFF dan BFF / microservice).
Nicholas Shanks
1
Ya itu poin yang bagus. Biasanya saat Anda memiliki layanan mikro yang membangun tim dan tim yang membuat aplikasi bersudut, misalnya, dan tim pengembang itu lebih tipe front-end yang tidak suka harus bekerja melawan sekelompok layanan kecil yang murni. Meskipun saya tidak melihat alasan apa pun Anda tidak dapat menggunakan pola yang sama untuk mengabstraksi layanan mikro dan agregasi menjadi fasad yang lebih dapat digunakan untuk pelanggan Anda, sehingga layanan mikro dapat diubah tanpa memengaruhi fasad.
Luke Puplett
Titik akhir API harus memodelkan kebutuhan domain dan bisnis. Kode untuk menyelesaikan masalah tersebut dan menghindari rekayasa berlebihan untuk mematuhi spesifikasi yang ketat dan tidak fleksibel dari waktu ke waktu. REST hanyalah pedoman.
Victorio Berra