Model binding adalah proses otomatis ASP.NET Core mengambil data dari request (baik dari route, query string, header, maupun body) dan mengubahnya menjadi object C# yang bisa langsung dipakai di dalam action method, menghilangkan kebutuhan parsing manual data request satu per satu.
Validation bekerja berdampingan dengan model binding, memastikan data yang masuk memenuhi aturan tertentu sebelum diproses lebih lanjut, baik melalui data annotation yang ditulis langsung di model, maupun validasi custom yang lebih kompleks untuk aturan bisnis spesifik.
Artikel ini membahas cara kerja model binding untuk berbagai sumber data, penerapan data annotation untuk validasi dasar, serta cara memeriksa dan merespons hasil validasi yang gagal dengan pesan error yang informatif bagi konsumen API.
Model Binding Otomatis ke Object Kompleks
Model binding mengubah JSON body menjadi object C# otomatis
Data Annotation untuk Validasi Dasar
Data annotation mendefinisikan aturan validasi langsung pada property
Memeriksa ModelState Secara Manual
ModelState.IsValid memeriksa hasil validasi data annotation
Validasi Custom dengan IValidatableObject
IValidatableObject untuk validasi yang melibatkan beberapa property
Custom Validation Attribute untuk Aturan Bisnis Spesifik
Membuat ValidationAttribute kustom untuk aturan yang tidak tersedia bawaan
Data annotation bawaan seperti [Required], [StringLength], dan [Range] cukup untuk validasi format sederhana, tetapi banyak aturan bisnis nyata membutuhkan logika yang lebih spesifik, misalnya validasi usia minimal, format nomor telepon sesuai operator tertentu, atau kombinasi dua field yang saling bergantung. Untuk kasus seperti ini, ASP.NET Core memungkinkan pembuatan custom validation attribute dengan mewarisi kelas ValidationAttribute dan meng-override method IsValid.
Keunggulan menaruh aturan di dalam custom attribute dibandingkan menulis if-else manual di action method adalah reusability dan konsistensi pesan error. Attribute seperti [MinimumAge(17)] bisa dipasang ulang pada DTO lain tanpa duplikasi kode, dan karena ModelState divalidasi otomatis sebelum action method dieksekusi (berkat [ApiController]), response 400 BadRequest beserta pesan error sudah terbentuk tanpa perlu menulis pengecekan tambahan di dalam controller.
Untuk validasi yang melibatkan lebih dari satu properti sekaligus, seperti memastikan tanggal selesai tidak boleh lebih awal dari tanggal mulai, pendekatan yang lebih tepat adalah mengimplementasikan interface IValidatableObject pada DTO tersebut, karena ValidationAttribute standar hanya menerima nilai satu properti tunggal dan tidak memiliki akses langsung ke properti lain dalam objek yang sama.
FluentValidation sebagai Alternatif Data Annotation
FluentValidation memisahkan seluruh aturan validasi ke class tersendiri
Data annotation seperti [Required] dan [EmailAddress] cukup praktis untuk aturan sederhana, tetapi menumpuk banyak atribut pada satu DTO membuat class tersebut bercampur antara definisi struktur data dan logika validasi. FluentValidation menawarkan pendekatan berbeda dengan memisahkan seluruh aturan validasi ke dalam class validator tersendiri yang mewarisi AbstractValidator
Sintaks fluent seperti RuleFor(x => x.Password).MinimumLength(8) lebih ekspresif untuk aturan kompleks dibanding merangkai banyak atribut data annotation, terutama ketika sebuah properti membutuhkan beberapa kondisi sekaligus atau validasi yang bergantung pada properti lain lewat method When() atau DependentRules(). Pendekatan ini juga lebih mudah diuji secara terpisah karena validator bisa diinstansiasi langsung di unit test tanpa perlu menjalankan seluruh pipeline HTTP. Pesan error pun bisa disesuaikan per aturan lewat WithMessage, termasuk mendukung penempatan placeholder dinamis seperti nilai minimum yang dilanggar.
Setelah AddFluentValidationAutoValidation() didaftarkan, validator akan otomatis dijalankan sebelum action method dieksekusi, persis seperti mekanisme ModelState bawaan pada data annotation, sehingga migrasi dari data annotation ke FluentValidation tidak mengubah cara controller menerima request yang sudah tervalidasi. Tim yang mengelola banyak DTO dengan aturan validasi rumit umumnya lebih memilih FluentValidation karena skalabilitasnya lebih baik dibanding menumpuk atribut pada class yang sama. Validator juga bisa menerima dependency lewat constructor, misalnya untuk memeriksa keunikan email langsung ke database saat validasi dijalankan.
IValidatableObject untuk Validasi yang Melibatkan Lebih dari Satu Field
Data annotation seperti Required atau Range bekerja per properti secara independen dan tidak bisa membandingkan nilai dari dua field sekaligus dalam satu aturan. IValidatableObject memberi tempat khusus untuk aturan yang bergantung pada kombinasi beberapa nilai, misalnya memastikan tanggal selesai tidak lebih awal dari tanggal mulai, tanpa perlu menulis validator eksternal terpisah untuk kasus yang masih tergolong sederhana dan hanya melibatkan satu model saja.
Karena interface ini dipanggil otomatis oleh framework setelah proses model binding selesai, hasil validasinya langsung masuk ke ModelState yang sama dengan validasi attribute biasa, sehingga action tidak perlu membedakan dari mana sumber error tersebut berasal. Untuk aturan bisnis yang jauh lebih kompleks dan melibatkan pengecekan ke database, pendekatan FluentValidation biasanya lebih mudah dirawat dibanding menumpuk banyak logika pengecekan langsung di dalam class model.
Kesalahan Umum yang Sering Terjadi
Mengandalkan Validasi Client-Side Saja
Validasi yang hanya dilakukan di sisi client (misalnya JavaScript) bisa dilewati dengan mudah oleh pengguna yang mengirim request langsung ke API, sehingga validasi di sisi server melalui data annotation tetap wajib ada sebagai lapisan pertahanan utama.
Tidak Memeriksa ModelState Sebelum Memproses Data
Pada controller yang tidak ditandai [ApiController] (seperti controller MVC biasa), lupa memeriksa ModelState.IsValid secara manual bisa menyebabkan data yang sebenarnya tidak valid tetap diproses lebih lanjut.
Menaruh Logika Bisnis Kompleks di Dalam Data Annotation
Data annotation sebaiknya hanya dipakai untuk validasi format sederhana; logika bisnis yang kompleks dan melibatkan pengecekan ke database sebaiknya ditangani di layer service, bukan dipaksakan ke dalam atribut validasi model.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Data annotation memberikan validasi yang cepat dan deklaratif langsung pada model, sangat cocok untuk aturan sederhana seperti field wajib diisi atau rentang nilai tertentu, dengan sedikit kode yang perlu ditulis.
Untuk validasi yang lebih kompleks dan melibatkan aturan bisnis yang mungkin berubah seiring waktu, library validasi eksternal seperti FluentValidation menawarkan pemisahan logika validasi dari model itu sendiri, yang bisa lebih mudah diuji dan dipelihara dibanding menumpuk banyak data annotation pada satu class.
Ringkasan
Model binding menghilangkan kebutuhan parsing data request secara manual, sementara validation memastikan data yang masuk memenuhi aturan yang ditentukan sebelum diproses lebih lanjut. Kombinasikan data annotation untuk validasi sederhana dengan IValidatableObject atau library eksternal untuk aturan yang lebih kompleks sesuai kebutuhan aplikasi.
Seri Belajar .NET Core:
← Sebelumnya: Routing dan Controller di ASP.NET Core
→ Selanjutnya: Dependency Injection di ASP.NET Core (segera terbit)