Hapus lunak di REST API

gambar

Agar pengguna tidak merasa sakit karena kehilangan data yang tidak dapat diperbaiki, ada baiknya memikirkan penghapusan lunak. Dengan penghapusan lunak, catatan tidak secara fisik dihapus dari database, tetapi hanya ditandai sebagai dihapus. Ini membuatnya mudah untuk memulihkan data dengan mengatur ulang bendera.

Baru-baru ini saya menerapkan penghapusan lunak di salah satu layanan REST kami. Mereka yang tertarik dengan apa yang saya lakukan, saya mengundang Anda untuk kucing.

Wajib masuk


Perdebatan tentang apakah akan menggunakan penghapusan ringan sudah sangat tua. Lihat saja holivar panjang di sini dan di sini .

Yang paling masuk akal adalah posisi yang menurutnya semuanya tergantung situasi. Ada kasus-kasus ketika penghapusan lunak nyaman atau bahkan perlu, ada kasus-kasus ketika argumen lawan penghapusan lunak perlu mendapat perhatian. Omong-omong, argumen penting terhadap penghapusan lunak adalah jawaban yang datang dari 2018: jika kita berbicara tentang akun pengguna, maka penghapusan lunak bertentangan dengan GDPR .

Kami memutuskan bahwa dalam layanan kami untuk penyimpanan dokumen, penghapusan lunak diperlukan.

Pendekatan tenang


Jika kita ingin menerapkan penghapusan lunak dalam suatu layanan, kita perlu memahami bagaimana tampilan dari sudut pandang antarmuka. Pencarian di Internet menunjukkan bahwa pertanyaan umum yang dimiliki orang adalah apakah akan menggunakan DELETE {resource} seperti sebelumnya, atau lebih baik menggunakan metode PATCH sebagai ganti badan yang menyertakan sesuatu seperti {status: 'dihapus'} .

Di sini, pendapat orang-orang itu tegas: perlu untuk menggunakan DELETE seperti sebelumnya. Dari sudut pandang klien, penghapusan juga merupakan penghapusan di Afrika. Tidak ada yang berubah: jika sumber daya dihapus, itu menjadi tidak dapat diakses; jika klien ingin menghapus sumber daya, ia tahu bahwa metode HTTP DELETE adalah untuk tujuan ini. Tidak perlu mendedikasikan klien secara detail tentang bagaimana layanan mengimplementasikan penghapusan.

Tapi selain itu, saya khawatir tentang pertanyaan tentang cara memulihkan sumber daya yang dihapus. Tentu saja, masalah ini diselesaikan dengan mengelola basis data. Namun, saya ingin dapat melakukan ini melalui REST API. Dan di sini kita mengalami konflik. Ternyata klien masih perlu didedikasikan untuk detail implementasi?

Pencarian untuk waktu yang lama tidak membuahkan hasil, sampai saya menemukan artikel yang bagus oleh Dan Yoder . Artikel ini meneliti semantik dari berbagai permintaan HTTP dan menyarankan bahwa alih-alih penghapusan fisik, pindahkan sumber daya jarak jauh ke arsip . Selain itu, alangkah baiknya jika DELETE mengembalikan tautan ke sumber daya yang diarsipkan. Pengguna selalu dapat mengembalikan sumber daya yang dihapus dengan mengirimkan permintaan POST ke arsip.

Desain


Layanan REST kami dibangun di atas ASP.NET Web API menggunakan Entity Framework. Seperti yang saya katakan, saya melakukan penghapusan lunak untuk sumber daya yang disebut dokumen.

Jadi, pertama-tama Anda perlu menambahkan kolom ke tabel terkait. Sebagai bendera, saya menggunakan stempel waktu yang disebut Dihapus. Jika nilainya bukan NULL, sumber daya dianggap dihapus. Selain itu, penting untuk memiliki informasi tentang siapa yang menghapus sumber daya.

ALTER TABLE Documents ADD Deleted datetime NULL, DeletedBy int NULL GO 

Tindakan HAPUS di controller sekarang hanya akan mengatur nilai-nilai bidang ini daripada secara fisik menghapus catatan. Selain itu, DELETE akan mengembalikan tubuh dengan referensi standar ke dokumen yang diarsipkan:

 { "links": { "archive": "documents/{id}/deleted" } } 

Sebenarnya, ini adalah poin penting: tautan membantu klien memahami bahwa dokumen tidak dihapus, tetapi dipindahkan .

Pengontrol baru untuk dokumen yang diarsipkan harus menyediakan metode berikut:
DAPATKAN dokumen / dihapusMendapat koleksi semua dokumen yang dihapus
DAPATKAN dokumen / {id} / dihapusMengembalikan dokumen yang dihapus
Dokumen POST / {id} / dihapusMemulihkan dokumen yang dihapus;
tidak membutuhkan tubuh; mengembalikan 201 Dibuat
HAPUS dokumen / {id} / dihapusSecara fisik menghapus dokumen

Implementasi


Awalnya, saya berencana untuk menambahkan dua tampilan ke database saya:

 CREATE VIEW DeletedDocuments AS SELECT * FROM Documents WHERE Deleted IS NOT NULL GO CREATE VIEW AvailableDocuments AS SELECT * FROM Documents WHERE Deleted IS NULL GO 

Tampak bagi saya bahwa ini akan lebih sedikit masalah: daripada mengatur kondisi dalam kode, saya hanya mendapatkan dua properti DbSet yang berbeda dalam konteks DB saya. Benar, Anda harus memiliki dua entitas identik dalam model, tetapi itu adalah properti objek POCO dalam konteks EF - setiap tabel sesuai dengan tepat satu entitas.

By the way, pandangan dalam SQL dapat berguna untuk Kerangka Entitas dalam hal lain: dengan bantuan mereka, misalnya, Anda bisa merujuk ke tabel dari database lain jika Anda tidak ingin membuat beberapa konteks DB.

Namun, dalam kasus saya, nomor dengan tampilan tidak lulus. Selama otorisasi, Anda harus bekerja dengan semua dokumen, karena pengguna memiliki hak yang sama untuk menghapus dokumen seperti yang sudah ada.

Oleh karena itu, saya memutuskan untuk hanya memiliki satu Dokumen DbSet di DbContext, dan dalam kode setiap kali saya mencari tahu apa yang sebenarnya dibutuhkan saat ini:

 var availableDocuments = DbContext.Documents.Where(d => d.Deleted == null); var deletedDocuments = DbContext.Documents.Where(d => d.Deleted != null); var allDocuments = DbContext.Documents; 

Sumber Daya Terkait


Dokumen adalah sumber daya yang terkait dengan sumber daya lainnya. Misalnya, kami memiliki alias dokumen. Artinya, Anda bisa mendapatkan dokumen tidak hanya dengan path dokumen / {id} , tetapi juga oleh path dokumen / {alias} , di mana alias adalah string unik.

Setelah menghapus dokumen, semua alias yang terkait dengannya harus menjadi "tidak terlihat": jika sebelumnya klien menerima daftar semua alias menggunakan dokumen GET / alias, maka setelah menghapus dokumen, alias-alias dari daftar tersebut akan hilang.

Tapi mereka tetap di database! Kami ingin memberikan kemampuan untuk memulihkan dokumen dalam keadaan di mana dokumen itu dihapus. Ini dapat menyebabkan kebingungan bagi klien: ia mencoba menambahkan alias baru untuk dokumen lain, daftar yang dikembalikan dari dokumen GET / alias tidak mengandung baris seperti itu, dan layanan tetap menolak untuk menambahkannya.

Saya rasa ini bukan masalah serius. Namun demikian, jika Anda perlu menyelesaikannya, Anda dapat menambahkan dokumen GET titik akhir / dihapus / alias . Kemudian semuanya jatuh pada tempatnya: layanan tidak dapat menambahkan alias, karena nilai seperti itu sudah digunakan oleh dokumen jarak jauh.

Mungkin timbul pertanyaan: apakah perlu membuang alias dari daftar yang dikembalikan dari dokumen / alias ? Biarkan mereka tinggal! Saya tidak berpikir bahwa keputusan seperti itu akan benar. Kemudian, ternyata daftar alias akan berisi tautan rusak, karena layanan akan mengembalikan 404 Tidak Ditemukan jika klien mencoba untuk mendapatkan dokumen yang dihapus dengan alias. Jika menyangkut sumber daya anak yang terkait dengan dokumen, maka perilaku harus persis sama seperti jika kita menghapus dokumen secara fisik.

Pembersihan arsip


Penghapusan lunak, selain dapat dengan mudah memulihkan data, memiliki beberapa keunggulan lainnya. Operasi hapus dalam basis data relasional adalah operasi yang mahal. Dan jika bahkan menghapus satu record mengarah ke penghapusan cascading record di tabel lain, maka ini penuh dengan deadlock. Oleh karena itu, penghapusan lunak lebih cepat dan lebih dapat diandalkan daripada penghapusan fisik.

Tetapi ada satu kelemahan signifikan. Basis mulai tumbuh.

Oleh karena itu, pada tahap akhir, Anda harus mengurus pembersihan otomatis arsip. Anda dapat, tentu saja, membersihkan pangkalan secara manual, tetapi lebih baik untuk mengotomatiskan proses ini. Jika kami secara langsung menetapkan tanggal kedaluwarsa objek jarak jauh, katakanlah, 30 hari, maka klien dapat menampilkan halaman arsip di mana elemen-elemen yang masa hidupnya mendekati akhir akan disorot.

Tangan saya belum mencapai tugas ini. Kami berencana untuk menambahkan ke sistem tugas kami tugas yang sehari sekali akan menjalankan kueri SQL sederhana yang menghapus semua objek busuk dari arsip. Sebagai parameter, tugas harus mengambil tanggal kedaluwarsa. Penting untuk memastikan bahwa nilai saat ini dari parameter ini disimpan di suatu tempat di satu tempat. Maka akan mungkin untuk menerapkan metode dalam layanan yang mengembalikan nilai ini ke klien.

Source: https://habr.com/ru/post/id440886/


All Articles