12 Factor Apps: Manajemen Konfigurasi pada Go dengan Viper
Dalam kaidah 12 Factor Apps, konfigurasi atau config adalah hal yang selalu ada dalam web service. Config biasa digunakan untuk mengatur database credentials (username dan password database), hingga mengatur API Key untuk layanan pihak ketiga.
Dalam konsep 12 Factor Apps, config pada suatu service wajib dipisah dari source code. Berikut adalah contoh source code yang tidak sesuai dengan kaidah 12 Factor Apps:
Dalam contoh di atas, DATABASE_USER dan DATABASE_PASSWORD mestinya tidak disimpan pada string di file source code tersebut, melainkan harus berada di file terpisah atau lebih baik lagi jika berada di dalam environment variables.
Config harus dipisah dari source code karena:
- Config yang disimpan di dalam source code akan masuk ke dalam version control system, hal ini tidak bijak karena memungkinkan data-data sensitif dan rahasia seperti API Key dan database credentials terekspos ke khalayak luas.
- Jika config di-hardcode ke dalam source code, maka kita akan kehilangan fleksibilitas config yang seharusnya bisa dengan mudah disesuaikan saat melakukan deployment.
Menggunakan Environment Variable
Kita bisa memindahkan config DATABASE_USER dan DATABASE_PASSWORD ke dalam environment variable di sistem operasi Linux/MacOS dengan menjalankan perintah:
$ export DATABASE_USER=nadia
$ export DATABASE_PASSWORD=a_strong_passwerd
Pada sistem operasi Windows dengan menjalankan perintah berikut di Command Prompt:
SET "DATABASE_USER=nadia"
SET "DATABASE_PASSWORD=a_strong_passwerd"
Setelah itu, source code bisa kita ganti seperti ini:
Menggunakan environment variable untuk config berjumlah sedikit dan sederhana tidaklah rumit, dan sebenarnya cukup untuk menyelesaikan beberapa tipe pekerjaan.
Namun cara ini tidak ideal jika kita punya banyak config, apalagi jika kita sering berganti-ganti source code seperti kalau kita mengerjakan microservices. Beberapa kekurangan dari cara ini yaitu:
- Tidak operating system-agnostic: tiap operating system punya cara berbeda untuk mengatur environment variable. Linux dan MacOS mungkin sama, namun Windows berbeda, belum lagi operating system lainnya.
- Tidak ada cara untuk mengatur default value: apa yang terjadi jika kita lupa mengatur environment variable di laptop kita? Value yang dibaca oleh
os.Getenv
akan bernilai""
(empty string), hal ini bisa menyebabkan error saat run-time. - Tidak scalable dan tidak fleksibel: menggunakan cara ini, config akan susah diatur jika jumlahnya banyak, bayangkan berapa banyak
export ENVVAR=value
yang kita harus lakukan jika jumlah config nya banyak? Kita bisa menyimpan seluruh perintah tersebut dalam satu file.sh
atau.bat
, namun akan muncul kembali masalah nomor (1).
Selain itu, config hanya bisa diatur melalui environment variable, tidak bisa melalui file seperti JSON atau YAML, tidak bisa dengan remote config systems seperti etcd atau Consul.
Kekurangan tersebut dapat diselesaikan dengan menggunakan library viper
.
Menggunakan Viper
Viper adalah library config untuk go yang dibuat oleh spf13, library ini memiliki banyak fitur seperti:
- Mengatur default value.
- Membaca config dari environment variable, file JSON, hingga file YAML.
- Membaca config dari remote config systems seperti etcd atau Consul.
Untuk menggunakan Viper di source code, pertama lakukan:
go get github.com/spf13/viper
Lalu, import di dalam source code:
import "github.com/spf13/viper"
Setelah itu, kita bisa menginisialisasi dengan:
viper.AutomaticEnv()
Akhirnya, untuk membaca value dari config sebagai tipe datastring
dengan:
viper.GetString("DATABASE_USER")
Selain tipe string
, kita juga bisa membaca tipe primitive lainnya dengan:
- Tipe
bool
menggunakan:viper.GetBool("KEY")
- Tipe
float64
menggunakan:viper.GetFloat64("KEY")
- Tipe
int
menggunakan:viper.GetInt("KEY")
- Tipe
time.Time
menggunakan:viper.GetTime("KEY")
- Tipe
time.Duration
menggunakan:viper.GetDuration("KEY")
Atau tipe data slice dengan:
- Tipe
[]string
menggunakan:viper.GetStringSlice("KEY")
- Tipe
[]int
menggunakan:viper.GetIntSlice("KEY")
Mengatur default value
Sebelum baris viper.AutomaticEnv()
, kita bisa mengatur default value di viper dengan baris berikut:
viper.SetDefault("DATABASE_USER", "postgres")
Melakukan override value
Value dari config yang telah dibaca dapat ditimpa dengan baris berikut:
viper.Set("DATABASE_USER", "sarah")
Membaca config dari file .yaml
Pertama-tama, buat file config.yaml
atau nama lain yang diinginkan, contoh isi file seperti ini:
DATABASE_USER=nadia
DATABASE_PASSWORD=a_strong_passwerd
Setelah itu, tambahkan baris berikut di source code:
viper.SetConfigName("config")
viper.SetConfigType("yaml")viper.AddConfigPath(".") // lokasi file config.yamlerr := viper.ReadInConfig() // Baca file config.yamlif err != nil {
// jika gagal membaca file config.yaml:
panic(fmt.Errorf("Gagal baca config: %s \n", err))
}
Baris viper.AddConfigPath(".")
berarti bahwa viper akan mencari file config.yaml
pada folder yang sama dengan source code.
Lalu kita dapat mendapatkan value dari config dengan baris:
viper.GetString("DATABASE_USER")
Saran: Jangan commit
file config.yaml
Anda.
Contoh source code lengkap
Berikut adalah contoh source code untuk menggunakan viper, mulai dari mengatur default value, membaca dari environment variable, membaca dari file .yaml, melakukan override value:
Pembelajaran lebih lanjut
Ada banyak fitur lainnya yang ditawarkan oleh library Viper, namun akan menjadi cukup panjang dan lebar jika penulis jabarkan di sini satu persatu, silakan menyelami library Viper di repository GitHub.
Terima kasih telah membaca tulisan ini, semoga memeperkaya teknik go Anda!
12 Factor Apps: https://12factor.net/
spf13/viper: https://github.com/spf13/viper