Belajar Gin - Configuration & Environment
Series/Belajar Gin/Episode 10
Episode 10 of 23

Belajar Gin - Configuration & Environment

Episode ini mengelola konfigurasi aplikasi Gin: variabel lingkungan dengan os.Getenv, file .env via godotenv, dan Viper untuk konfigurasi terpusat. Kalian juga belajar menyusun config struct serta implementasi graceful shutdown dengan http.Server dan signal.NotifyContext.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Sebuah aplikasi tidak boleh memuat rahasia atau pengaturan di dalam kode. Episode 10 ini membedah configuration & environment: cara membaca variabel lingkungan, memuat file .env untuk pengembangan, mengelola konfigurasi kompleks dengan Viper, dan yang tidak kalah penting — menghentikan server dengan bersih lewat graceful shutdown.

Kenapa bagian ini krusial? Koneksi database, port, dan token seharusnya bisa berbeda antara lingkungan development, staging, dan production tanpa mengubah kode. Graceful shutdown memastikan request yang sedang berjalan selesai sebelum proses mati, sehingga pengguna tidak mengalami error di tengah pemrosesan.

Variabel Lingkungan dengan os.Getenv

Membaca dan Memverifikasi

Cara paling dasar membaca konfigurasi adalah os.Getenv. Untuk variabel yang wajib ada, kombinasikan dengan os.LookupEnv:

Baca variabel lingkungan
port := os.Getenv("PORT")
if port == "" {
    port = "8080"
}
 
dbURL, ok := os.LookupEnv("DATABASE_URL")
if !ok {
    log.Fatal("DATABASE_URL wajib diisi")
}

os.Getenv("PORT") mengembalikan string kosong jika variabel tidak ada, sehingga kalian perlu fallback. os.LookupEnv mengembalikan dua nilai sehingga tahu pasti apakah variabel terdefinisi — penting untuk variabel wajib seperti DATABASE_URL.

godotenv untuk File .env

Memuat File .env Saat Development

Di development, menyetel puluhan variabel lewat terminal tidak praktis. godotenv memuat file .env ke environment:

Install godotenv
go get github.com/joho/godotenv
File .env
PORT=8080
DATABASE_URL=postgres://arman:rahasia@localhost:5432/belajargin?sslmode=disable
REDIS_ADDR=localhost:6379
LOG_LEVEL=info
Load .env di awal main
func main() {
    if err := godotenv.Load(); err != nil {
        log.Println("tidak ada .env, pakai environment system")
    }
    cfg := config.Load()
    // ...
}

Panggil godotenv.Load() di awal main sebelum membaca konfigurasi. Jangan pernah meng-commit file .env — gunakan .env.example sebagai templat. Di production, variabel disuntikkan langsung oleh orchestrator atau platform, bukan dari file.

Konfigurasi Terpusat dengan Viper

Membaca File dan Environment Sekaligus

Untuk konfigurasi yang lebih kompleks, viper menggabungkan file konfigurasi, environment, dan flag:

Install Viper
go get github.com/spf13/viper
Inisialisasi Viper
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AutomaticEnv()
 
if err := viper.ReadInConfig(); err != nil {
    log.Printf("config file tidak terbaca: %v", err)
}

viper.AutomaticEnv() membuat setiap key bisa dioverride variabel lingkungan dengan pola nama yang sama. Contohnya key database.url bisa dioverride variabel DATABASE.URL atau pola lain sesuai konfigurasi. Ini memberi prioritas: environment mengalahkan file.

Config Struct dan Injeksi ke Handler

Struct Config

Kumpulkan semua pengaturan dalam satu struct agar bisa diinjeksi:

config.go
type Config struct {
    Port        string
    DatabaseURL string
    MaxConns    int
    RedisAddr   string
    LogLevel    string
}
 
func Load() Config {
    return Config{
        Port:        os.Getenv("PORT"),
        DatabaseURL: os.Getenv("DATABASE_URL"),
        MaxConns:    mustInt("MAX_CONNS", 10),
        RedisAddr:   os.Getenv("REDIS_ADDR"),
        LogLevel:    os.Getenv("LOG_LEVEL"),
    }
}

Fungsi config.Load() Config menjadi satu-satunya tempat membaca environment. Handler dan service tidak perlu memanggil os.Getenv lagi — mereka menerima Config lewat konstruktor seperti pola injeksi di episode 8.

Injeksi ke Handler

Dengan injeksi, handler bisa diuji dengan config apa pun:

NewServer(cfg config.Config) menyuntikkan config ke seluruh lapisan. Karena semua ketergantungan datang dari satu tempat, mengganti environment cukup mengubah nilai environment, bukan kode.

Graceful Shutdown

Memakai http.Server dan signal.NotifyContext

engine.Run langsung memblokir goroutine, sehingga sulit menghentikan dengan bersih. Ganti dengan http.Server dan tangani sinyal:

Graceful shutdown
srv := &http.Server{
    Addr:         ":" + cfg.Port,
    Handler:      r,
    ReadTimeout:  10 * time.Second,
    WriteTimeout: 15 * time.Second,
}
 
go func() {
    if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
        log.Fatalf("server gagal: %v", err)
    }
}()
 
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
<-ctx.Done()
 
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
 
if err := srv.Shutdown(shutdownCtx); err != nil {
    log.Fatalf("shutdown gagal: %v", err)
}
log.Println("server berhenti dengan bersih")

signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) membatalkan context ketika pengguna menekan Ctrl+C atau orchestrator mengirim SIGTERM. Setelah itu srv.Shutdown(shutdownCtx) menunggu request aktif selesai maksimal 10 detik, lalu menutup koneksi. Inilah pola yang akan dipakai ulang di episode 21 untuk arsitektur production.

Penutup

Inti yang harus dibawa pulang:

  • os.Getenv dengan fallback, os.LookupEnv untuk variabel wajib.
  • godotenv memuat file .env untuk development, jangan di-commit.
  • viper menggabungkan file konfigurasi dan environment dengan prioritas environment.
  • Kumpulkan pengaturan dalam config.Config lalu injeksikan ke handler.
  • http.Server + signal.NotifyContext untuk graceful shutdown.
  • srv.Shutdown memberi waktu request aktif selesai sebelum proses mati.

Di episode 11 selanjutnya kita akan membedah error handling & logging — menangkap error dengan c.Error, custom error type, middleware error handler dengan response JSON terpadu, serta integrasi slog ke middleware Gin untuk log yang terstruktur.

Belajar Gin - Configuration & Environment | Belajar Gin