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

Belajar Echo - Configuration & Environment

Episode ini mengajarkan manajemen konfigurasi yang benar: variabel lingkungan dengan os.Getenv, godotenv untuk development, Viper untuk kebutuhan kompleks, struct config terpusat, server HTTP custom dengan ReadTimeout dan WriteTimeout, serta graceful shutdown.

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

Pendahuluan

Kredensial database, secret JWT, dan port server tidak boleh di-hardcode. Konfigurasi yang benar membuat aplikasi kalian bisa berpindah dari development ke production tanpa mengubah satu baris kode pun. Episode ini mengajarkan fondasi 12-factor app pada level praktis.

Episode 10 ini membahas variabel lingkungan dengan os.Getenv, godotenv untuk development, Viper untuk konfigurasi kompleks, struct config terpusat, server HTTP custom dengan ReadTimeout dan WriteTimeout, serta graceful shutdown.

Variabel Lingkungan dan Struct Config

Membaca dengan os.Getenv

os.Getenv adalah cara paling dasar dan sebenarnya cukup untuk sebagian besar aplikasi:

Membaca variabel lingkungan
port := os.Getenv("PORT")
if port == "" {
	port = "8080"
}

Selalu berikan default. os.Getenv mengembalikan string kosong saat variabel tidak ada, jadi pola if port == "" menjaga aplikasi tetap berjalan meski konfigurasi belum lengkap.

Struct Config Terpusat

Jangan sebarkan pemanggilan os.Getenv ke seluruh kode. Kumpulkan semua konfigurasi dalam satu struct yang diisi sekali saat startup:

Struct config terpusat
type Config struct {
	Port        string
	DatabaseURL string
	JWTSecret   string
	Environment string
}
 
func Load() Config {
	return Config{
		Port:        getEnv("PORT", "8080"),
		DatabaseURL: getEnv("DATABASE_URL", ""),
		JWTSecret:   getEnv("JWT_SECRET", ""),
		Environment: getEnv("ENVIRONMENT", "development"),
	}
}

Struct Config ini kemudian dioper ke seluruh komponen lewat dependency injection — pola yang sudah kalian bangun di episode 8.

godotenv dan Viper

godotenv untuk File .env

Di development, menulis variabel di terminal tiap kali sangat tidak nyaman. godotenv memuat file .env ke dalam environment saat proses dimulai:

Install godotenv
go get github.com/joho/godotenv
Memuat file .env
if err := godotenv.Load(); err != nil {
	slog.Warn("file .env tidak ditemukan, pakai environment")
}
cfg := Load()

Jangan pernah commit file .env ke repository — pastikan masuk .gitignore. Untuk secret, selalu gunakan environment dari sistem atau secret manager.

Viper untuk Konfigurasi Kompleks

Saat konfigurasi bertambah — file YAML, key dari banyak sumber, dan override otomatis — Viper menjadi pilihan:

Install Viper
go get github.com/spf13/viper
Viper membaca file dan environment
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
	slog.Warn("konfigurasi file tidak dibaca", "err", err)
}
port := viper.GetString("server.port")

Dengan viper.AutomaticEnv(), variabel lingkungan secara otomatis menjadi override terhadap nilai file. Ini kombinasi yang umum dipakai di production.

Server HTTP Custom

ReadTimeout dan WriteTimeout

e.Start memakai pengaturan default yang kurang aman untuk production. Bangun http.Server sendiri agar waktu tunggu terkontrol:

Server HTTP custom dengan timeout
s := &http.Server{
	Addr:         ":" + cfg.Port,
	ReadTimeout:  30 * time.Second,
	WriteTimeout: 30 * time.Second,
	IdleTimeout:  120 * time.Second,
}
 
e.HideBanner = true
e.HidePort = true
if err := e.StartServer(s); err != nil {
	e.Logger.Fatal(err)
}

ReadTimeout melindungi dari koneksi lambat, WriteTimeout mencegah handler yang menggantung, dan IdleTimeout menutup koneksi yang tidak aktif. e.StartServer(s) menjalankan server custom ini bersama router Echo.

Graceful Shutdown

Menghentikan Server dengan Rapi

Server production harus berhenti dengan rapi: menyelesaikan request yang sedang berjalan sebelum mati, bukan langsung memutus koneksi. Gunakan signal.NotifyContext dan e.Shutdown:

Graceful shutdown penuh
ctx, stop := signal.NotifyContext(context.Background(),
	os.Interrupt, syscall.SIGTERM)
defer stop()
 
go func() {
	if err := e.StartServer(s); err != nil &&
		err != http.ErrServerClosed {
		e.Logger.Fatal(err)
	}
}()
 
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := e.Shutdown(shutdownCtx); err != nil {
	e.Logger.Fatal(err)
}
slog.Info("server berhenti dengan rapi")

Saat Ctrl+C atau SIGTERM diterima, e.Shutdown memberi waktu 10 detik bagi request yang sedang berjalan untuk selesai sebelum proses keluar. Ini adalah pola yang wajib di semua aplikasi production.

Penutup

Episode 10 membuat konfigurasi aplikasi kalian dewasa: variabel lingkungan dibaca sekali lewat struct Config, godotenv memudahkan development, Viper menangani kebutuhan kompleks, server HTTP custom dengan timeout melindungi resource, dan graceful shutdown menghentikan server tanpa memutus request aktif.

Inti yang harus dibawa pulang:

  • Konfigurasi dibaca dari environment, dikumpulkan dalam struct Config.
  • os.Getenv butuh default; jangan pernah hardcode secret.
  • godotenv memuat .env untuk development; jangan commit filenya.
  • Viper memadukan file config dan override environment.
  • http.Server custom menetapkan ReadTimeout dan WriteTimeout.
  • signal.NotifyContext dan e.Shutdown menghasilkan graceful shutdown.
  • Pola shutdown: jalankan server di goroutine, tunggu sinyal, lalu shutdown.

Di episode 11 selanjutnya kita akan membahas error handling & loggingHTTPError dan custom error handler, format RFC 9457 Problem Details untuk respons API yang konsisten, logging terstruktur dengan slog via RequestLogger, dan integrasi dengan log aggregator.

Belajar Echo - Configuration & Environment | Belajar Echo