Building flexible applications requires us to separate configuration from code. This allows us to easily adapt the application to different environments, such as local computers, production servers, or even user devices. That way, configurations such as database connection details can be changed without having to modify the application's core code.
Separating configuration from code has several advantages. First, we can change the configuration without having to redeploy the entire application. Second, it improves application security because sensitive information, such as database passwords, is no longer exposed in the code. Finally, the application becomes easier to maintain and develop. Viper is one of the popular Golang libraries for configuration management, supporting many types of configuration files, such as JSON, YAML, env files, properties, and others.
Project Initialization
The first step is to create a project first, then install the viper package.
mkdir learn-viper && cd learn-viper
then init go modules
go mod init learn-viper
install viper
go get github.com/spf13/viper
Setting Application Configuration
Here we will only give examples of popular configuration files such as JSON files, YAML files, and env files.
Create new file config.json
and the following code
{
"app": {
"name": "golang-viper",
"env": "development"
},
"database": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"pass": "secrete123",
"name": "my_db",
"show_sql": true
}
}
Create New File config.yaml
and the following code
app:
name: "golang-viper"
env: "development"
database:
host: "localhost"
port: 5432
user: "postgres"
pass: "secrete123"
name: "my_db"
show_sql: true
create new file local.env
and the following code
APP_NAME=golang-viper
APP_ENV=development
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASS=secrete123
DB_NAME=my_db
DB_SHOW_SQL=true
Use Viper and test your configuration
install package testing
go get github.com/stretchr/testify
create new file config_test.go
and the following code
package learn_viper
import (
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)
func TestViper(t *testing.T) {
var config *viper.Viper = viper.New()
assert.NotNil(t, config)
}
func TestJSON(t *testing.T) {
config := viper.New()
config.SetConfigName("config")
config.SetConfigType("json")
config.AddConfigPath(".")
// read config
err := config.ReadInConfig()
assert.Nil(t, err)
assert.Equal(t, "golang-viper", config.GetString("app.name"))
assert.Equal(t, "development", config.GetString("app.env"))
assert.Equal(t, "localhost", config.GetString("database.host"))
assert.Equal(t, 5432, config.GetInt("database.port"))
assert.Equal(t, "postgres", config.GetString("database.user"))
assert.Equal(t, "secrete123", config.GetString("database.pass"))
assert.Equal(t, "my_db", config.GetString("database.name"))
assert.Equal(t, true, config.GetBool("database.show_sql"))
}
func TestYAML(t *testing.T) {
config := viper.New()
config.SetConfigName("config")
config.SetConfigType("yaml")
config.AddConfigPath(".")
// read config
err := config.ReadInConfig()
assert.Nil(t, err)
assert.Equal(t, "golang-viper", config.GetString("app.name"))
assert.Equal(t, "development", config.GetString("app.env"))
assert.Equal(t, "localhost", config.GetString("database.host"))
assert.Equal(t, 5432, config.GetInt("database.port"))
assert.Equal(t, "postgres", config.GetString("database.user"))
assert.Equal(t, "secrete123", config.GetString("database.pass"))
assert.Equal(t, "my_db", config.GetString("database.name"))
assert.Equal(t, true, config.GetBool("database.show_sql"))
}
func TestENVFile(t *testing.T) {
config := viper.New()
config.SetConfigName("local")
config.SetConfigType("env")
// config.AutomaticEnv() // if env not file
config.AddConfigPath(".")
// read config
err := config.ReadInConfig()
assert.Nil(t, err)
assert.Equal(t, "golang-viper", config.GetString("APP_NAME"))
assert.Equal(t, "development", config.GetString("APP_env"))
assert.Equal(t, "localhost", config.GetString("DB_HOST"))
assert.Equal(t, 5432, config.GetInt("DB_PORT"))
assert.Equal(t, "postgres", config.GetString("DB_USER"))
assert.Equal(t, "secrete123", config.GetString("DB_PASS"))
assert.Equal(t, "my_db", config.GetString("DB_NAME"))
assert.Equal(t, true, config.GetBool("DB_SHOW_SQL"))
}
Running go test ./... -v
will run all the test cases in the package.
Conclusion
In conclusion, using the Viper package in Go is very useful for managing configuration applications. It supports multiple configuration file formats, including JSON, YAML, and env files. Viper makes it easy to manage and read configuration files of different types. We can also use Viper to read environment variables and command-line flags.
Viper provides a simple and convenient way to read and write configuration values in our application. It also provides a convenient way to override configuration values with environment variables, command line flags, or remote configuration sources.
In summary, Viper is a powerful tool for managing application configuration in Go. It's easy to use, flexible, and provides a lot of features for managing configuration values.