Om-yum-yum dan validasi data

Halo semuanya! Mari kita bicara sedikit tentang validasi data. Apa yang rumit dan mengapa harus dibutuhkan, katakanlah, dalam sebuah proyek yang ditulis dalam naskah? Mengetik naskah cukup baik mengontrol semuanya, tetap untuk memeriksa input pengguna maksimum. Artinya, untuk melemparkan selusin pelanggan tetap ke dalam proyek dan semuanya, tampaknya, bisa menutup topik, tapi ... Jauh dari biasanya, dan dalam kasus web, hampir tidak pernah, seluruh proyek dalam basis kode tunggal dan menggunakan jenis yang sama. Di persimpangan basis kode seperti itu, situasi muncul ketika menunggu tidak sesuai dengan kenyataan dan di sini naskah bukan lagi asisten. Beberapa contoh:


  • Bagian klien dari aplikasi menerima data dari API dan memvalidasinya. Pertama, API dapat tiba-tiba dan kadang-kadang tanpa pemberitahuan berubah, dan kedua, "orang-orang server" sendiri kadang-kadang tidak tahu apa yang dapat dilakukan API mereka, misalnya, di beberapa bidang, alih-alih array yang dijamin, bahkan jika kosong, bulan purnama mungkin diberikan null . Saat menggambarkan data pada klien, programmer tampaknya menentukan apa yang klien tahu bagaimana bekerja dengan dan jika ada masalah, maka jauh lebih menyenangkan untuk segera melihat pesan di konsol tentang sumber masalah, daripada mengambil bug yang tidak bisa dimengerti yang sudah keluar dari lapisan tampilan (dan itu baik jika segera diperhatikan). Juga sekarang sudah ada solusi ( 1 , 2 ) yang memungkinkan transfer jenis dari server ke klien. Saya belum mencoba untuk melakukannya, tetapi sangat mungkin bahwa ini adalah masa depan.
  • Situasi sebaliknya adalah ketika server memeriksa parameter yang dikirim untuk segera menghentikan pemrosesan permintaan jika mereka tidak memenuhi yang diharapkan. Saya pikir tidak perlu ada perincian tentang mengapa ini penting untuk dilakukan.
  • Validasi data sebelum menyimpannya dalam database juga tidak akan berlebihan. Misalnya, Anda dapat melihat bagaimana itu diatur dalam salah satu sepeda saya: MaraquiaORM # Validasi .

Saya pikir contoh-contohnya cukup meyakinkan dan sekarang tidak ada perasaan yang dapat Anda lakukan dengan pelanggan tetap yang sederhana, karena ini bukan hanya tentang input pengguna, tetapi tentang validasi kompleks, biasanya bersarang pada beberapa level data. Perpustakaan khusus sudah diperlukan di sini. Dan tentu saja ada! Kebetulan bahwa selama 10 tahun terakhir, setiap kali saya memulai proyek baru, saya mencoba menggunakan perpustakaan lain di dalamnya, menyesuaikannya dengan kebutuhan saya. Dan setiap kali terjadi kesalahan, yang kadang-kadang mengarah pada penggantian subjek tes di tengah perkembangan aktif. Saya tidak akan berbicara tentang semua opsi yang saya pelajari, saya hanya akan mengatakan tentang yang diuji dalam proyek saat ini.


ketik-cek


Github


Perpustakaan kecil dan cukup nyaman. Rangkaian ini digambarkan sebagai string. Menggunakan string multi-line, Anda dapat menggambarkan struktur yang cukup rumit:


 `{ ID: String, creator: { fname: String | Null, mname: String | Null, lname: String | Null, email: [String] } | Undefined, sender: Maybe { name: String, email: String }, type: Number, subject: String, ... }` 

Ada beberapa kekurangan yang cukup serius:


  • IDE sama sekali tidak membantu dengan sekumpulan skema, yang sangat mengganggu ketika beralih ke naskah.
  • Pesan kesalahan yang hampir tidak berguna. Saya belum pernah menggunakan perpustakaan ini selama lebih dari setahun dan mungkin ada sesuatu yang berubah (dilihat dari kodenya, tidak). Pesan dalam gaya "string yang diharapkan, diterima nol". Sekarang bayangkan, Anda memiliki array potongan untuk 200 objek, masing-masing memiliki bidang dengan string, dan hanya dalam satu objek salah satu bidang telah rusak. Bagaimana menemukan bidang ini? Lihat semua 200 item? Saya menderita berkali-kali dan itu benar - benar menghancurkan hidup saya, merusak kesan perpustakaan. Biasanya saya tidak ingin tahu apa yang diharapkan dan diterima di sana, tetapi saya ingin membuka skema data dan menemukan bidang yang diperlukan di dalamnya dan sama dengan data itu sendiri. Dengan kata lain, dalam pesan kesalahan, sangat penting untuk memiliki keypath ke tempat yang tepat dalam data / skema, dan apa yang diharapkan di sana dan tiba sama sekali dapat dihilangkan.
  • Cukup sepele, tentu saja, tetapi lekukan dalam contoh di atas tidak akan hilang ketika kode dikompresi.

Joi


Github
Versi Browser: joi-browser


Mungkin perpustakaan paling terkenal tentang hal ini dengan banyak fitur dan API tanpa akhir. Pada awalnya saya menggunakannya di server dan itu menunjukkan dirinya dengan sempurna. Pada titik tertentu, saya memutuskan untuk menggantinya dengan type-check pada klien. Pada saat itu, saya hampir tidak mengontrol ukuran bungkusan, tidak ada masalah dengan ini. Namun seiring berjalannya waktu, aplikasi ini berkembang pesat dan di Internet seluler, pengunduhan aplikasi pertama sama sekali tidak nyaman. Diputuskan untuk mengatur pemuatan komponen yang malas. Laporan webpack-bundle-analyzer menunjukkan sekelompok raksasa dalam bundel dan mereka semua dengan mudah pergi ke potongan yang dibuat oleh webpack. Semuanya kecuali Joi . Banyak komponen berkomunikasi dengan server dan semua respons server divalidasi, yaitu, memasukkan Joi ke dalam beberapa jenis chunk tidak masuk akal, itu hanya akan selalu memuat tepat setelah yang utama. Pada titik tertentu, bundel utama tampak seperti ini: tyts . Tentu saja, keinginan abadi muncul untuk melakukan sesuatu. Saya menginginkan perpustakaan yang sama nyamannya, tetapi jauh lebih sedikit.


Yup


Github


Dalam readme mereka berjanji tentang Joi sama, tetapi dalam ukuran cocok untuk frontend. Bahkan, itu hanya sekitar dua kali lebih kecil, yaitu, Yup masih perpustakaan terbesar di bundel utama. Selain itu, kerugian tambahan muncul:


  • Pustaka default melewatkan semua yang undefined . Terus-menerus menulis .required() tidak terlalu menyenangkan, dan saya suka lebih baik ketika awalnya semuanya tidak mungkin dan di mana diizinkan. Joi memiliki opsi presence: 'required' untuk mengkonfigurasi perilaku ini. Saya membuat permintaan dengan nomor neraka 666 , tetapi sejauh ini penulis diam.
  • Tidak ada cara untuk memeriksa nilai suatu objek, memungkinkan semua kunci. Joi menggunakan object.pattern untuk ini, dengan argumen pertama menerima string apa pun. Mungkin masih mungkin untuk entah bagaimana keluar dari sana, dan penulis dapat memperbaiki minus pertama, tetapi mengingat ukurannya, saya tidak ingin menunggu atau mengedit sesuatu sendiri.

Ow


Github


Pemohon berikutnya akhirnya ternyata sangat kecil, ditambah lagi dia tidak membuatnya terus-menerus menulis () mana Anda dapat melakukannya tanpa itu. Misalnya, Anda dapat menulis validator yang memungkinkan string atau undefined sebagai berikut:


 let optionalStringValidator = ow.optional.string; ow(optionalStringValidator, '1'); // Ok ow(optionalStringValidator, undefined); // Ok 

Hebat! Bagaimana dengan null ? Membalik semua dokumentasi, saya menemukan metode berikut:


 ow.any(ow.optional.string, ow.null); 

Oh horor! Ketika saya mencoba untuk menulis ulang bagian dari validasi dalam proyek, saya hampir mematahkan jari saya saat mengetik ini. Saya ow.nullable masalah menambahkan ow.nullable , yang dikirim ke sini . Singkatnya, mereka mengatakan bahwa null tidak diperlukan sama sekali. Argumen yang diberikan di sana juga cukup memadai mengingat baris pertama di readme mereka:


Validasi argumen fungsi untuk manusia

Yaitu, perpustakaan ini adalah untuk memvalidasi nilai-nilai yang datang sebagai argumen untuk fungsi. Tampaknya, mereka tidak benar-benar mengandalkan struktur bersarang besar yang berasal dari server.
Studi lebih lanjut dan upaya untuk menggunakan mengungkapkan beberapa fitur yang, sekali lagi, dijelaskan dengan baik oleh baris yang sama di readme, tetapi tidak cocok untuk saya. Ini sebenarnya perpustakaan yang cukup bagus, hanya untuk beberapa keperluan lain.




Di sekitar sini, saya sudah benar-benar lelah untuk menyerah dan memutuskan untuk menulis perpustakaan saya dengan blackjack dan perawan. Ya, ya, saya kembali kepada Anda dengan sepeda berikutnya :). Bertemu:


Omyumyum


Beberapa contoh:


 import om from 'omyumyum'; const isOptionalNumber = om.number.or.undefined; isOptionalNumber('1'); // => false isOptionalNumber(1); // => true isOptionalNumber(undefined); // => true 

.or dapat digunakan sebanyak yang Anda inginkan dengan meningkatkan opsi yang layak:


 om.number.or.string.or.null.or.undefined; 

Dalam hal ini, fungsi yang hampir biasa dihasilkan secara konstan yang mengambil argumen apa pun dan mengembalikan boolean .
Jika Anda ingin fungsi untuk melempar kesalahan jika tes gagal:


 om(om.number, '1'); //  TypeError 

Atau dengan kari:


 const isNumberOrThrow = om(om.number); isNumberOrThrow('1') //  TypeError 

Fungsi yang dihasilkan tidak cukup biasa, karena memiliki metode tambahan. .or sudah ditampilkan, bagian dari metode akan bergantung pada tipe yang dipilih (lihat API ), misalnya string dapat ditingkatkan dengan ekspresi reguler:


 const isNonEmptyString = om.string.pattern(/\S/); // == `om.string.nonEmpty` isNonEmptyString(' '); // => false isNonEmptyString('1'); // => true 

Dan untuk objek, Anda dapat menentukan bentuknya:


 const isUserData = om.object.shape({ name: om.string, age: om.number.or.vacuum // `.or.vacuum` == `.or.null.or.undefined` }); isUserData({}); // => false isUserData({ age: 20 }) // => false isUserData({ name: '' }); // => true isUserData({ name: '', age: null }); // => true isUserData({ name: '', age: 20 }); // => true 

Keypath yang dijanjikan ke tempat masalah:


 om(om.array.of(om.object.shape({ name: om.string })), [{ name: '' }, { name: null }]); //  TypeError('Type mismatch at "[1].name"') 

Jika fitur .custom(validator: (value: any) => boolean) tidak cukup, Anda selalu dapat menggunakan .custom(validator: (value: any) => boolean) :


 const isEmailOrPhone = om.custom(require('is-email')).or.custom(require('is-phone')); isEmailOrPhone('test@test.test'); // => true 

Stok juga diharapkan. .and digunakan untuk menggabungkan dan meningkatkan jenis:


 const isNonZeroString = om.string.and.custom(str => str.length > 0); // == `om.string.nonZero` isNonZeroString(''); // => false isNonZeroString('1'); // => true 

.and lebih diutamakan daripada .custom() , tetapi karena .custom() menerima validator dengan bentuk yang sama persis seperti yang dibuat oleh perpustakaan, ini dapat dielakkan:


 //      `age`,   `birthday` om.object.shape({ name: om.string }).and.custom( om.object.shape({ age: om.number }) .or.object.shape({ birthday: om.date })] ); 

Anda dapat terus meningkatkan validator yang dibuat sebelumnya. Yang lama tidak rusak sama sekali. Mari kita coba untuk memperbaiki isUserData dibuat sebelumnya:


 const isImprovedUserData = isUserData.and.object.shape({ friends: om.array.of(isUserData).or.vacuum }); isImprovedUserData({ name: '', age: 20, friends: [{ name: '', age: 18 }] }); // => true 

Nah, tinggal .not :


 const isNotVacuum = om.not.null.and.not.undefined; // == `om.not.vacuum` isNotVacuum(1); // => true isNotVacuum(null); // => false isNotVacuum(undefined); // => false 

Metode lain yang tersedia dapat ditemukan di API perpustakaan.


Keuntungan perpustakaan:


  • Sintaksis linier dengan .not , .not , .not dan minimum tanda kurung. Dalam kombinasi dengan naskah naskah autocomplete, himpunan berubah menjadi kesenangan.
  • Berat kecilnya bahkan dibandingkan dengan Ow (hampir 10 kali lebih sedikit (minify + gzip)), dan dibandingkan dengan Joi perpustakaan itu seperti bulu di sebelah gunung.
  • Nama yang bagus :)

Kontra perpustakaan:


  • Lebih sedikit jenis dan pengubahnya. Dan tidak mungkin ada lebih banyak. Ketiga skenario penggunaan yang diberikan di awal artikel (sesuatu tentang persimpangan dan basis kode) mengasumsikan transfer data teks biasa, dalam kebanyakan kasus ini adalah JSON. Artinya, menurut pendapat saya, perpustakaan seperti itu harus mendukung jenis yang mungkin di JSON, ditambah jenis yang undefined dan beberapa yang umum digunakan. Ow sama Ow untuk beberapa alasan, dijejali dengan dukungan untuk semua jenis array yang diketik dan omong kosong lainnya. Saya pikir ini berlebihan.
  • Tidak dapat mengonversi data seperti Joi . Saya pikir Joi juga sangat buruk. Setidaknya saya tidak memiliki cukup kemampuannya dan, jika perlu, saya melakukan transformasi dengan alat yang sama sekali berbeda. Mungkin ini adalah arah pengembangan lebih lanjut untuk omyumyum .

Itu saja! Jika Anda menyukai artikel, suka, berlangganan saluran dan semoga sukses)).

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


All Articles