Routing adalah mekanisme yang menentukan controller dan action method mana yang akan menangani sebuah request berdasarkan URL dan HTTP verb yang dikirim client. ASP.NET Core menyediakan attribute routing yang memungkinkan pola URL didefinisikan langsung di atas controller dan method menggunakan atribut.
Selain menentukan tujuan request, routing juga menangani ekstraksi parameter dari URL, baik dari segment path, query string, maupun body request, dan secara otomatis mengonversinya ke tipe data yang sesuai dengan parameter method melalui mekanisme model binding.
Artikel ini membahas cara mendefinisikan route dengan attribute routing, berbagai cara menerima parameter, serta konvensi penamaan route yang membuat API lebih mudah dipahami dan konsisten.
Attribute Routing Dasar
Route template menentukan pola URL yang dilayani setiap action
Mengambil Parameter dari Query String
FromQuery mengambil parameter dari query string URL
Mengambil Data dari Body Request
FromBody mengambil dan mendeserialisasi JSON dari body request
Route Constraint untuk Validasi Tipe Parameter
Route constraint membedakan route berdasarkan tipe parameter
Selain parameter tunggal, model binding juga mendukung binding otomatis ke object kompleks dari kombinasi query string, misalnya sebuah class FilterProduk dengan beberapa property akan otomatis terisi dari beberapa parameter query string sekaligus tanpa perlu menuliskan setiap parameter satu per satu di signature method, selama nama property pada class cocok dengan nama parameter pada query string tersebut.
Attribute Routing Lanjutan: Route Constraint dan Konflik Rute
Route constraint memisahkan dua endpoint dengan pola segmen yang mirip
Route constraint seperti {id:int} atau {code:alpha} berfungsi sebagai filter tambahan pada proses pencocokan URL, bukan sekadar dokumentasi tipe data. Tanpa constraint, dua endpoint dengan template mirip seperti {id} dan {code} akan saling bentrok karena router tidak tahu endpoint mana yang dituju, dan ASP.NET Core akan melempar AmbiguousMatchException saat kedua rute sama-sama cocok dengan segmen yang diterima.
Constraint bawaan yang tersedia mencakup int, bool, datetime, decimal, guid, length(min,max), min(value), max(value), dan alpha, dan constraint ini bisa digabung dengan tanda titik dua berurutan seperti {id:int:min(1)} yang berarti segmen tersebut harus berupa integer sekaligus bernilai minimal satu. Kombinasi ini membuat validasi format URL terjadi di level routing, sebelum action method sempat dieksekusi sama sekali.
Penting dicatat bahwa route constraint bukan pengganti validasi input yang sesungguhnya, karena perannya hanya untuk membantu router memilih action yang tepat ketika ada beberapa kandidat rute yang mirip. Validasi bisnis seperti memastikan id tersebut benar-benar ada di database tetap harus dilakukan secara eksplisit di dalam action method atau lewat lapisan service terpisah.
Route Group dan Endpoint Metadata pada Minimal API
MapGroup menggabungkan path prefix, autentikasi, dan metadata OpenAPI sekaligus
Pada pendekatan berbasis controller, pengelompokan rute biasanya dilakukan lewat [Route("api/[controller]")] di level class, sedangkan pada Minimal API peran serupa diambil alih oleh MapGroup yang memungkinkan sekumpulan endpoint berbagi prefix path, kebijakan otorisasi, dan metadata OpenAPI tanpa duplikasi konfigurasi di setiap endpoint individual. Fitur ini membuat Minimal API tetap terorganisir walau tidak memiliki struktur class formal seperti controller. MapGroup juga bisa disusun bertingkat, misalnya grup /api/admin dipecah lagi menjadi sub grup /api/admin/users dan /api/admin/reports yang masing-masing mewarisi pengaturan dari grup induknya.
Method RequireAuthorization() yang dipanggil pada level grup berlaku untuk seluruh endpoint di dalamnya, sehingga menambah endpoint admin baru ke dalam grup tersebut otomatis mewarisi aturan otorisasi yang sama tanpa risiko developer lupa menambahkan atribut [Authorize] pada endpoint baru tersebut. Pola ini mengurangi celah keamanan yang sering terjadi akibat kelalaian manusia saat menambah endpoint satu per satu. Filter tambahan seperti validasi header kustom pun bisa dipasang di level grup lewat AddEndpointFilter, berlaku konsisten untuk semua endpoint anggotanya.
WithName dan WithOpenApi memberi metadata tambahan yang dipakai oleh dokumentasi Swagger serta mekanisme pembuatan link seperti Results.CreatedAtRoute, mirip dengan nama route pada routing berbasis controller. Kombinasi metadata ini penting agar Minimal API yang terlihat sederhana secara kode tetap menghasilkan dokumentasi API yang informatif dan tidak kalah lengkap dibanding dokumentasi yang dihasilkan dari atribut controller tradisional. Tanpa WithOpenApi, Swagger tetap bisa membaca endpoint secara otomatis, tetapi deskripsi dan ringkasannya akan kosong atau hanya berupa nama method generik.
Content Negotiation: Mendukung Response JSON dan XML Sekaligus
Secara default ASP.NET Core hanya mengembalikan response dalam format JSON karena output formatter untuk XML tidak didaftarkan pada konfigurasi awal controller. Dengan menambahkan AddXmlSerializerFormatters, framework akan memilih formatter yang sesuai berdasarkan header Accept yang dikirim klien, sehingga action yang sama dapat melayani konsumen lama yang masih mengharapkan format XML tanpa perlu menulis controller atau endpoint terpisah khusus untuk kebutuhan tersebut.
Content negotiation jarang dibutuhkan jika seluruh konsumen API sudah sepakat memakai JSON sebagai format tunggal, sehingga menambahkan formatter XML tanpa kebutuhan nyata hanya akan menambah kompleksitas dan beban testing. Fitur ini lebih relevan ketika API harus menjembatani sistem lama yang hanya bisa memproses XML, misalnya integrasi dengan layanan pihak ketiga atau sistem legacy yang sudah berjalan sejak lama dan sulit diubah formatnya.
Kesalahan Umum yang Sering Terjadi
Membuat Route yang Ambigu Antar Action Method
Dua action method dengan route template yang bisa cocok dengan URL yang sama tanpa constraint pembeda akan menyebabkan AmbiguousMatchException saat aplikasi dijalankan dan route tersebut diakses.
Lupa Menandai Parameter Body dengan FromBody
Tanpa FromBody, ASP.NET Core akan mencoba mengambil parameter object kompleks dari query string atau form, bukan dari JSON body, menyebabkan parameter tersebut selalu null meski client sudah mengirim data dengan benar.
Tidak Konsisten dalam Penamaan Route Antar Endpoint
Campuran gaya penamaan route seperti /api/produk-list dan /api/DaftarProduk dalam satu aplikasi yang sama membuat API terasa tidak konsisten dan lebih sulit diingat oleh konsumen API.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Attribute routing memberikan kejelasan karena definisi route berada tepat di atas action method yang bersangkutan, memudahkan developer melihat langsung URL apa yang akan menjalankan method tertentu tanpa perlu mencari konfigurasi terpisah.
Convention-based routing (routing berdasarkan konvensi tanpa atribut eksplisit) bisa mengurangi duplikasi penulisan route pada aplikasi dengan pola URL yang sangat konsisten, namun kurang eksplisit dan lebih sulit dilacak dibanding attribute routing untuk API dengan struktur URL yang bervariasi.
Ringkasan
Routing dan controller bekerja sama untuk mengarahkan request ke action method yang tepat, dengan attribute routing memberikan kejelasan definisi URL langsung di kode. Pahami berbagai sumber parameter seperti FromQuery dan FromBody, serta manfaatkan route constraint untuk menghindari ambiguitas antar endpoint yang serupa.
Seri Belajar .NET Core:
← Sebelumnya: Memahami Middleware pada ASP.NET Core
→ Selanjutnya: Model Binding dan Validation di ASP.NET Core