AGA — Address Gateway
On this page
- Sekilas
- Yang dikerjakannya
- A. Menyajikan hirarki administratif setingkat demi setingkat
- B. Memakai kode wilayah resmi sebagai identitas
- C. Mencari wilayah dari potongan namanya
- D. Membawa datanya sendiri
- E. Melaporkan dengan jujur apakah ia sanggup menjawab
- Antarmuka
- Standar
- Di dalamnya
- Keputusan rancangan
- Spesifikasi
- Terkait
- Istilah
AGA — Address Gateway — adalah service HTTP kecil berbahasa Rust yang menjawab satu pertanyaan bagi aplikasi mana pun yang meminta alamat Indonesia: provinsi apa saja yang ada, kabupaten dan kota mana yang termasuk satu provinsi, kecamatan mana yang termasuk satu kabupaten, dan desa mana yang termasuk satu kecamatan. Seluruh hirarki administratif ikut di dalamnya — 38 provinsi sampai 83.768 desa, berkunci kode wilayah resmi Kementerian Dalam Negeri — dan disajikan sebagai empat lookup pendek, masing-masing satu tingkat lebih dalam dari sebelumnya.
Saya membangunnya sekali lalu memakainya ulang di setiap project yang punya form alamat, karena semuanya butuh dropdown bertingkat yang sama, kode yang sama, dan pencarian yang sama. Menyimpan salinan delapan puluh ribu desa di dalam tiap aplikasi berarti delapan puluh ribu baris yang harus dijaga tetap identik di mana-mana. Satu service dengan satu salinan data membuat semua aplikasi mendapat jawaban yang sama.
Sekilas
| Bahasa & framework | Rust, dengan actix-web dan sqlx di atas PostgreSQL |
|---|---|
| Arsitektur | Clean Architecture |
| Versi | 2.1.0 |
| Status | Stabil, berjalan di production |
| Bentuk | Service HTTP mandiri di belakang API gateway, dipakai ulang lintas project |
| Kode sumber | Privat |
Yang dikerjakannya
A. Menyajikan hirarki administratif setingkat demi setingkat
Form alamat mengisi dropdown-nya berurutan: provinsi dulu, lalu kabupaten atau kota di dalamnya, lalu kecamatan, lalu desa. AGA mengikuti urutan itu persis. Tiap lookup menerima kode yang dipilih satu tingkat di atasnya dan mengembalikan tingkat di bawahnya, terurut menurut nama, jadi form tak pernah mengunduh lebih dari daftar yang akan segera ditampilkannya.
B. Memakai kode wilayah resmi sebagai identitas
Tiap wilayah dikenali dari kode bertitik Kementerian Dalam Negeri — 11 untuk provinsi, 11.01 untuk kabupaten, 11.01.01 untuk kecamatan, 11.01.01.2001 untuk desa — bukan dari nomor internal. Aplikasi bisa menyimpan kode itu di samping alamat dan membacanya kembali bertahun-tahun kemudian, dari AGA atau dari sumber lain yang memakai kode yang sama.
C. Mencari wilayah dari potongan namanya
Setiap lookup menerima kata pencarian opsional yang dicocokkan di bagian mana pun dari nama, tanpa peduli huruf besar-kecil. User yang mengetik beberapa huruf nama desa hanya melihat desa yang cocok. Kata pencarian dipangkas spasinya, yang kosong berarti tanpa filter, dan jumlah hasilnya dibatasi supaya pencarian satu huruf tetap murah.
D. Membawa datanya sendiri
Tabel dan seluruh data ikut dikompilasi ke dalam service, dalam bentuk migration database. Database kosong menjadi API wilayah yang lengkap dalam satu kali start, tanpa langkah import terpisah dan tanpa file yang harus diunduh.
E. Melaporkan dengan jujur apakah ia sanggup menjawab
Readiness check meminta jawaban sepele dari database dan baru melapor 200 bila jawaban itu datang, 503 bila tidak. Dengan begitu platform container atau service induk bisa membedakan AGA yang sekadar hidup dari AGA yang benar-benar bisa melayani.
Antarmuka
| Kemampuan | Kegunaan |
|---|---|
| Provinsi | semua provinsi |
| Kabupaten dan kota | kabupaten dan kota dalam satu provinsi |
| Kecamatan | kecamatan dalam satu kabupaten atau kota |
| Desa | desa dalam satu kecamatan |
| Readiness | apakah database menjawab; tanpa autentikasi |
| Versi | nama dan versi service; tanpa autentikasi |
AGA bisa dipasang di route mana pun pada gateway, dan setiap lookup menjawab dengan envelope yang sama, berisi request id kiriman pemanggil atau yang dibuat AGA sendiri:
Standar
| Standar | Yang dijaminnya di sini |
|---|---|
| Kode wilayah Kementerian Dalam Negeri | identitas yang dikenali sistem lain di Indonesia, divalidasi per tingkat |
| W3C Trace Context dan OpenTelemetry (OTLP, semantic conventions) | trace, log, dan metrics yang menyambung trace pemanggil lintas service |
| UUIDv7 | request id yang tak pernah bertabrakan dan terurut menurut waktu |
| OpenAPI 3.0.3 | kontrak setiap endpoint yang terbaca mesin |
Di dalamnya
AGA mengikuti Clean Architecture. Domain memegang keempat wilayah, format kodenya, serta aturan untuk nama dan kata pencarian. Lapisan application memegang satu use case per lookup beserta port yang dibutuhkannya — repository per tingkat, health check database, dan authenticator. PostgreSQL, identitas dari gateway, konfigurasi, dan telemetry masing-masing tinggal di lapisan infrastructure, dan satu composition root menjadi satu-satunya tempat yang mengenal keempat lapisan sekaligus. Karena tiap use case menerima repository-nya lewat port, 60 test-nya berjalan dengan repository in-memory dan health check palsu, tanpa database.
Keputusan rancangan
Data ikut di dalam binary, dan memuatnya adalah keputusan, bukan efek samping. Migration saya kompilasi ke dalam service, jadi image yang berjalan adalah image yang membawa data, dan tak ada deployment yang bisa memasangkan satu versi kode dengan versi wilayah yang lain. Menjalankannya bersifat opt-in lewat flag konfigurasi, sebab service yang menulis ulang skemanya setiap kali start adalah service yang bisa mengejutkan database production. Migration berjalan di koneksinya sendiri dengan statement logging dimatikan. Seed desa berupa satu insert hampir lima megabyte; library database mencatatnya utuh sebagai slow statement, dan satu catatan itu lebih besar dari batas yang diterima collector telemetry, sehingga collector membuang seluruh batch tempat ia tiba — termasuk log lain yang tak berkaitan. Saat start, service juga meminta jawaban sepele dari database dan mencatat hasilnya tanpa menolak start, supaya database yang masih booting tak ikut menjatuhkan service.
Setiap baris mengenal seluruh garis leluhurnya. Desa menyimpan kodenya sendiri dan juga kode kecamatan, kabupaten, dan provinsinya. Tiap kolom itu berindeks dan terikat ke tabel induknya. Ongkosnya beberapa byte per baris; imbalannya lookup yang tak pernah butuh join di tingkat mana pun, dan ruang untuk pertanyaan baru seperti "semua desa di provinsi ini" tanpa mengubah skema. Nama juga berindeks, untuk pencarian.
Input yang tak sah berhenti di pintu, dan data yang tak sah tak pernah keluar. Tiap tingkat punya format kodenya sendiri, diperiksa regular expression di domain sebelum query disusun. Kode yang cacat menjadi 400 dengan pesan yang menyebut field-nya, bukan daftar kosong yang tampak seperti jawaban. Nama dipangkas spasinya, tak boleh kosong, dan tak boleh melebihi lebar kolomnya. Aturan yang sama berlaku ke arah sebaliknya: baris database yang melanggarnya diperlakukan sebagai kegagalan server dan dicatat, tak diteruskan ke form. Kata pencarian dipangkas, dibatasi panjangnya, selalu dikirim ke database sebagai bound parameter dan tak pernah ditempel ke dalam query, dan hasilnya dibatasi serta terurut menurut nama.
Siap berarti database menjawab. Versi sebelumnya punya health check di root yang selalu menjawab 200 karena tak memeriksa apa pun. Container yang sudah kehilangan database-nya tetap tampak sehat, dan service di depannya tak bisa tahu. Saya menggantinya dengan readiness check di bawah prefix service sendiri, yang menjalankan query sepele dan mengembalikan 503 dengan body datar yang menyebut dependensi yang gagal — bentuk yang sama dengan module lain di sampingnya, supaya satu pemeriksaan gabungan bisa membaca semuanya. Check lama saya hapus, tak saya pertahankan berdampingan, dan test yang membuktikan 503 itu dibuktikan sendiri lewat sabotase: memaksa handler selalu menjawab 200 membuat test-nya gagal.
Identitas datang dari gateway, bukan dari token. AGA berada di belakang API gateway yang mengautentikasi setiap pemanggil dan hanya meneruskan identitas yang sudah terverifikasi — kontrak yang sama dengan module saya yang lain — dan identitas itu dicatat di trace request.
Satu kontrak, dijaga persis. Setiap respons membawa envelope yang sama dan request id — diterima dari pemanggil atau dibuat sendiri — yang juga dipantulkan di header. Body 400 satu-satunya pengecualian yang disengaja: ia tak memuat request id di dalam body, karena versi yang digantikan AGA pun tidak, dan aplikasi sudah mem-parse bentuk itu byte demi byte.
Setiap request bisa diikuti lintas service. Telemetry pindah dari menulis langsung ke Elasticsearch menjadi OpenTelemetry lewat collector. Trace context yang masuk dilanjutkan, sehingga satu lookup tampil sebagai anak dari halaman yang memintanya. Metrics memakai delta temporality, karena exporter Elasticsearch milik collector membuang histogram dan counter yang kumulatif. Metrics HTTP diberi label pola route, bukan path mentah, supaya seratus ribu kode tak berubah menjadi seratus ribu deret. Alamat client diambil dari header forwarded hanya bila datang dari trusted proxy, dan telemetry bisa dimatikan sehingga yang tersisa stdout, dengan flush saat shutdown ketika ia menyala. Jalur trace hanya melihat span: sebelum perubahan itu, setiap baris log terekspor dua kali, sekali sebagai span event dan sekali sebagai log record.
Ia penyedia, jadi pemakainya yang memegang deployment. Image dibangun dua tahap, berjalan sebagai user non-root, dan membaca konfigurasinya dari file yang di-mount. AGA tak lagi membawa deployment sendiri: tiap project yang memakainya menjalankannya di dalam stack project itu, dengan database dan collector-nya sendiri, karena project itulah yang tahu bagaimana ia di-backup dan ke mana telemetry-nya pergi.
Spesifikasi
| Masukan | Request dari aplikasi di belakang API gateway, membawa identitas yang terverifikasi |
|---|---|
| Hasil | Daftar wilayah beserta kode, kode induk, dan namanya, dalam satu envelope JSON |
| Data | 38 provinsi, 514 kabupaten dan kota, 7 277 kecamatan, 83 768 desa |
| Penyimpanan | PostgreSQL, dengan tabel dan data yang dipasang lewat migration tertanam |
| Batas | Kata pencarian dan hasilnya sama-sama dibatasi |
| Observability | Trace, log, dan metrics OpenTelemetry lewat OTLP, atau stdout saja |
| Test | 60, tanpa database |
| Berjalan sebagai | Image container yang dibangun dua tahap, sebagai user non-root, dengan konfigurasi di-mount dari file |
Terkait
Ke mana trace, log, dan metrics AGA pergi setelah meninggalkan service.
Istilah
- Hirarki administratif
- Empat tingkat wilayah Indonesia yang bersarang: provinsi, kabupaten atau kota, kecamatan, dan desa.
- Kode wilayah
- Identitas bertitik yang diberikan Kementerian Dalam Negeri kepada tiap wilayah, makin panjang di tiap tingkat, seperti
11.01.01.2001. - Migration
- Script berversi yang mengubah skema atau data database, dijalankan sekali dan dicatat supaya tak pernah dijalankan dua kali.
- Readiness check
- Endpoint yang melaporkan apakah service sanggup melayani request saat ini, bukan sekadar apakah prosesnya hidup.
- API gateway
- Service di depan service lain yang mengautentikasi pemanggil dan hanya meneruskan identitas yang sudah terverifikasi.
- Port
- Interface yang didefinisikan lapisan dalam dan diimplementasikan lapisan luar, supaya aturan tak pernah bergantung pada tool tertentu.
Technologies covered
- Rust
- PostgreSQL
- OpenTelemetry