Satu basis kode, banyak lingkungan: laptop pengembang, server staging, dan cluster produksi di Atlas. Kode aplikasi idealnya identik di ketiganya — yang berubah hanyalah ke mana koneksi diarahkan dan bagaimana koneksinya disetel. Menuliskan connection string langsung di kode menutup semua kemungkinan itu: pindah lingkungan berarti edit kode, dan kredensial ikut terbaca di repository. Solusi standarnya adalah environment variable — antarmuka antara kode dan lingkungan tempat kode berjalan. Chapter ini membahas anatomi connection string, pemilihan database dari konfigurasi, dan pola baca-validasi-gagal-cepat saat startup.
Connection String sebagai Kontrak #
Semua informasi koneksi dikemas dalam satu URI. Mongosh sendiri membawa URI yang bisa kita inspeksi:
db.getMongo()Output yang Dihasilkan:
mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.13.0Anatomi URI di atas, potongan demi potongan:
| Bagian | Contoh | Arti |
|---|---|---|
| Skema | mongodb:// | protokol (atau mongodb+srv:// untuk SRV record Atlas) |
| Kredensial | user:password@ | opsional; dikirim saat server meminta autentikasi |
| Host | 127.0.0.1:27017 | alamat dan port; SRV URI boleh tanpa port |
| Database default | /latihan_env | database untuk operasi yang tidak menyebut nama |
| Opsi | ?retryWrites=true&w=majority | setelan driver per koneksi |
Perhatikan bahwa mongosh menambahkan opsi miliknya sendiri (serverSelectionTimeoutMS, appName) — setiap klien boleh melengkapi URI dengan opsi tambahan. Karena seluruh kontrak hidup di satu string, memindahkan aplikasi antar lingkungan cukup mengganti nilai satu environment variable: MONGODB_URI.
Memilih Database dari Konfigurasi #
Database juga bagian konfigurasi, bukan konstanta di kode. Polanya: nama database dibaca dari variabel MONGODB_DB_NAME, lalu dipakai saat mengambil handle:
const dbDariKonfigurasi = "toko_dev" // dalam aplikasi: nilai MONGODB_DB_NAME
db = db.getSiblingDB(dbDariKonfigurasi)
db.getName()Output yang Dihasilkan:
toko_dev
toko_devgetSiblingDB(dbDariKonfigurasi) memindahkan database aktif sesuai nilai variabel, dan getName() mengonfirmasi pilihannya. Di aplikasi Node.js, pemilihan yang sama terjadi lewat client.db(cfg.dbName) dengan nama yang dibaca dari environment variable; di PyMongo lewat client[cfg.db_name]. Variabel yang lazim dipakai:
| Variabel | Isi | Contoh nilai |
|---|---|---|
MONGODB_URI | connection string lengkap | mongodb://127.0.0.1:27017/toko_dev?directConnection=true |
MONGODB_DB_NAME | nama database default | toko_dev / toko_prod |
APP_ENV / NODE_ENV | lingkungan berjalan | development / production |
MONGODB_POOL_SIZE | setelan pool (dibahas di Chapter Connection Pooling) | 10 |
Baca, Validasi, Gagal Cepat #
Aturannya: seluruh konfigurasi dibaca dan divalidasi di awal proses, sebelum ada request yang dilayani. Konfigurasi yang hilang harus menghentikan aplikasi dengan pesan yang jelas — bukan muncul sebagai kegagalan di tengah malam saat request pertama tiba. File berikut menerapkan pola itu sekaligus mengamarkan kredensial sebelum mencetak:
// baca-konfigurasi.js — baca konfigurasi dari environment variable, validasi, lalu uji koneksi
// Jalankan tanpa env var, lalu dengan env var:
// node baca-konfigurasi.js
// MONGODB_URI='mongodb://127.0.0.1:27017/?directConnection=true' \
// MONGODB_DB_NAME=latihan_env APP_ENV=development node baca-konfigurasi.js
const { MongoClient } = require("mongodb")
function bacaKonfigurasi() {
const wajib = ["MONGODB_URI", "MONGODB_DB_NAME", "APP_ENV"]
for (const nama of wajib) {
if (!process.env[nama]) {
throw new Error(`Environment variable ${nama} belum di-set`)
}
}
return {
uri: process.env.MONGODB_URI,
dbName: process.env.MONGODB_DB_NAME,
env: process.env.APP_ENV,
}
}
function samarkan(uri) {
return uri.replace(/\/\/([^:]+):([^@]+)@/, "//$1:***@")
}
async function main() {
const cfg = bacaKonfigurasi()
console.log("konfigurasi terbaca:", JSON.stringify({
uri: samarkan(cfg.uri),
dbName: cfg.dbName,
env: cfg.env,
}))
const client = new MongoClient(cfg.uri, { serverSelectionTimeoutMS: 5000 })
try {
await client.connect()
await client.db("admin").command({ ping: 1 })
const jumlahKoleksi = await client.db(cfg.dbName).collections()
console.log("koneksi OK — database", cfg.dbName, "dapat diakses,", jumlahKoleksi.length, "collection")
} finally {
await client.close()
}
}
main().catch(err => {
console.error("GAGAL:", err.message)
process.exit(1)
})Kita jalankan tiga skenario. Pertama, tanpa environment variable sama sekali:
node baca-konfigurasi.jsOutput yang Dihasilkan (pesan galat muncul di stderr, kode keluar 1):
GAGAL: Environment variable MONGODB_URI belum di-setKedua, konfigurasi lengkap tetapi memakai kredensial fiktif dewi_aplikasi:
MONGODB_URI='mongodb://dewi_aplikasi:[email protected]:27017/latihan_env?directConnection=true' \
MONGODB_DB_NAME=latihan_env APP_ENV=development node baca-konfigurasi.jsOutput yang Dihasilkan:
konfigurasi terbaca: {"uri":"mongodb://dewi_aplikasi:***@127.0.0.1:27017/latihan_env?directConnection=true","dbName":"latihan_env","env":"development"}
GAGAL: Authentication failed.Skenario kedua memperlihatkan dua hal sekaligus: fungsi samarkan() menyembunyikan password menjadi *** sebelum URI dicetak, dan galat autentikasi muncul seketika saat startup — bukan tersebar di log request. Ketiga, URI lokal tanpa kredensial (server latihan kita tidak mengaktifkan autentikasi):
MONGODB_URI='mongodb://127.0.0.1:27017/latihan_env?directConnection=true' \
MONGODB_DB_NAME=latihan_env APP_ENV=development node baca-konfigurasi.jsOutput yang Dihasilkan:
konfigurasi terbaca: {"uri":"mongodb://127.0.0.1:27017/latihan_env?directConnection=true","dbName":"latihan_env","env":"development"}
koneksi OK — database latihan_env dapat diakses, 0 collectionPadanan pola yang sama di PyMongo singkat saja — baca os.environ, validasi, gunakan:
# Padanan bacaKonfigurasi() dalam Python
import os
from pymongo import MongoClient
uri = os.environ.get("MONGODB_URI")
db_name = os.environ.get("MONGODB_DB_NAME")
if not uri or not db_name:
raise SystemExit("MONGODB_URI dan MONGODB_DB_NAME wajib di-set")
client = MongoClient(uri)
db = client[db_name]Konfigurasi Berbeda per Environment #
Nilai yang tepat di laptop tidak selalu tepat di produksi. Tabel berikut merangkum perbedaan yang paling sering di-set:
| Aspek | development | staging | production |
|---|---|---|---|
MONGODB_URI | localhost, tanpa TLS | cluster internal, TLS | Atlas/cluster, TLS + kredensial kuat |
maxPoolSize | kecil (5) | sedang (25) | dihitung dari kapasitas (Chapter Connection Pooling) |
serverSelectionTimeoutMS | longgar | sedang | ketat, agar gagal cepat |
appName (opsi URI) | toko-dev | toko-staging | toko-prod — penanda koneksi tiap lingkungan di log server |
Opsi appName layak jadi kebiasaan: nilainya muncul di log server dan currentOp, sehingga koneksi dari tiap lingkungan dapat dibedakan. Saat insiden terjadi, kemampuan menjawab “koneksi ini datang dari aplikasi mana” hanya bergantung pada satu opsi kecil yang disetel sejak awal.
Untuk pengembangan lokal, nilai-nilai ini biasa ditaruh di file .env dan dimuat otomatis oleh pustaka seperti dotenv (Node.js) atau python-dotenv. Prinsipnya tetap sama: file itu hanya mengisi environment variable — kode aplikasi tetap membaca process.env / os.environ, bukan file itu langsung. Dengan begitu, pindah ke container, orchestrator, atau platform yang menyuntikkan environment variable sendiri tidak mengubah satu baris kode pun.
Rangkuman #
- Seluruh kontrak koneksi hidup di satu URI (skema, kredensial, host, database default, opsi) — memindahkan lingkungan cukup mengganti
MONGODB_URI. - Nama database dibaca dari konfigurasi (
MONGODB_DB_NAME), bukan konstanta di dalam kode. - Baca dan validasi seluruh environment variable di awal proses; konfigurasi hilang berhenti dengan pesan jelas sebelum melayani request.
- Setelan pool, timeout, dan
appNameboleh berbeda per environment — nilai produksi dihitung, bukan disalin dari laptop.