12 Factor Apps: Manajemen Konfigurasi pada Go dengan Viper

Guntur Akhmad
Style Theory Engineering & Data

--

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:

  1. 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.
  2. 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:

  1. 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.
  2. 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.
  3. 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:

  1. Mengatur default value.
  2. Membaca config dari environment variable, file JSON, hingga file YAML.
  3. 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

--

--