Viper Examples
Viper is a configuration library fo Go. It has been my go to library for configs. Some of the best features of Viper are:
- Ability to unmarshal subsets of a configuration file into a Go struct
- Ability to override contents of a configuration file using OS environment variables
Here’s a brief example that demonstrates both features:
Assume you have a configuration file at $HOME/server.toml
resolve_dns = true
http_keep_alive = 5
[example_com]
doc_root = "/var/www/example_com"
allow_files = "*.html"
login_required = true
login_lockout_count = 3
[example_org]
doc_root = "/var/www/example_org"
allow_files = "*.html, *.jpg"
login_required = false
login_lockout_count = 5
Then you can utilize the configuration file using this snippet:
package main
import (
"fmt"
"github.com/spf13/viper"
"os"
)
func main() {
userHomeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
baseDir := fmt.Sprintf("%s", userHomeDir)
// This section demonstrates the ability to
// 1. Unmarshal a subtree using Sub()
// 2. Ability to override subtree configurations using SetEnvPrefix
//
// Run this via:
//
// COM_DOC_ROOT=123 ORG_DOC_ROOT=456 go run main.go
//
viper.SetConfigName("server")
viper.AddConfigPath(fmt.Sprintf("%s", baseDir))
if err := viper.ReadInConfig(); err != nil {
panic(err)
}
var sc ServerConf
if err := viper.Unmarshal(&sc); err != nil {
panic(err)
}
fmt.Printf("ServerConf:\n%+v\n", sc)
com_section := viper.Sub("example_com")
com_section.SetEnvPrefix("com")
com_section.AutomaticEnv() // Or viper.BindEnv("doc_root")
var vc_com VHostConf
if err := com_section.Unmarshal(&vc_com); err != nil {
panic(err)
}
fmt.Printf("example.com:\n%+v\n", vc_com)
org_section := viper.Sub("example_org")
org_section.SetEnvPrefix("org")
org_section.AutomaticEnv()
var vc_www VHostConf
if err := org_section.Unmarshal(&vc_www); err != nil {
panic(err)
}
fmt.Printf("example.org\n%+v\n", vc_www)
}
type ServerConf struct {
ResolveDNS bool `mapstructure:"resolve_dns"`
HttpKeepAlive int `mapstructure:"http_keep_alive"`
}
type VHostConf struct {
DocRoot string `mapstructure:"doc_root"`
AllowFiles string `mapstructure:"allow_files"`
LoginRequired bool `mapstructure:"login_required"`
LoginLockoutCount int `mapstructure:"login_lockout_count"`
}
Running the command COM_DOC_ROOT=123 ORG_DOC_ROOT=456 go run main.go
gets you
ServerConf:
{ResolveDNS:true HttpKeepAlive:5}
example.com:
{DocRoot:123 AllowFiles:*.html LoginRequired:true LoginLockoutCount:3}
example.org
{DocRoot:456 AllowFiles:*.html, *.jpg LoginRequired:false LoginLockoutCount:5}
The DocRoot from each vhost has been overriden with environment variables, allowing you to make changes quickly without touhing your configuration file, which is frequently useful when prototyping new software.