Getting Values From Viper

In Viper, there are a few ways to get a value depending on the value’s type.The following functions and methods exist:

  • Get(key string) : interface{}
  • GetBool(key string) : bool
  • GetFloat64(key string) : float64
  • GetInt(key string) : int
  • GetString(key string) : string
  • GetStringMap(key string) : map[string]interface{}
  • GetStringMapString(key string) : map[string]string
  • GetStringSlice(key string) : []string
  • GetTime(key string) : time.Time
  • GetDuration(key string) : time.Duration
  • IsSet(key string) : bool
  • AllSettings() : map[string]interface{}
    One important thing to recognize is that each Get function will return a zerovalue if it’s not found. To check if a given key exists, the IsSet() methodhas been provided.

Example:

  1. viper.GetString("logfile") // case-insensitive Setting & Getting
  2. if viper.GetBool("verbose") {
  3. fmt.Println("verbose enabled")
  4. }

Accessing nested keys

The accessor methods also accept formatted paths to deeply nested keys. Forexample, if the following JSON file is loaded:

  1. {
  2. "host": {
  3. "address": "localhost",
  4. "port": 5799
  5. },
  6. "datastore": {
  7. "metric": {
  8. "host": "127.0.0.1",
  9. "port": 3099
  10. },
  11. "warehouse": {
  12. "host": "198.0.0.1",
  13. "port": 2112
  14. }
  15. }
  16. }

Viper can access a nested field by passing a . delimited path of keys:

  1. GetString("datastore.metric.host") // (returns "127.0.0.1")

This obeys the precedence rules established above; the search for the pathwill cascade through the remaining configuration registries until found.

For example, given this configuration file, both datastore.metric.host anddatastore.metric.port are already defined (and may be overridden). If in additiondatastore.metric.protocol was defined in the defaults, Viper would also find it.

However, if datastore.metric was overridden (by a flag, an environment variable,the Set() method, …) with an immediate value, then all sub-keys ofdatastore.metric become undefined, they are “shadowed” by the higher-priorityconfiguration level.

Lastly, if there exists a key that matches the delimited key path, its valuewill be returned instead. E.g.

  1. {
  2. "datastore.metric.host": "0.0.0.0",
  3. "host": {
  4. "address": "localhost",
  5. "port": 5799
  6. },
  7. "datastore": {
  8. "metric": {
  9. "host": "127.0.0.1",
  10. "port": 3099
  11. },
  12. "warehouse": {
  13. "host": "198.0.0.1",
  14. "port": 2112
  15. }
  16. }
  17. }
  18.  
  19. GetString("datastore.metric.host") // returns "0.0.0.0"

Extract sub-tree

Extract sub-tree from Viper.

For example, viper represents:

  1. app:
  2. cache1:
  3. max-items: 100
  4. item-size: 64
  5. cache2:
  6. max-items: 200
  7. item-size: 80

After executing:

  1. subv := viper.Sub("app.cache1")

subv represents:

  1. max-items: 100
  2. item-size: 64

Suppose we have:

  1. func NewCache(cfg *Viper) *Cache {...}

which creates a cache based on config information formatted as subv.Now it’s easy to create these 2 caches separately as:

  1. cfg1 := viper.Sub("app.cache1")
  2. cache1 := NewCache(cfg1)
  3.  
  4. cfg2 := viper.Sub("app.cache2")
  5. cache2 := NewCache(cfg2)

Unmarshaling

You also have the option of Unmarshaling all or a specific value to a struct, map,etc.

There are two methods to do this:

  • Unmarshal(rawVal interface{}) : error
  • UnmarshalKey(key string, rawVal interface{}) : error
    Example:
  1. type config struct {
  2. Port int
  3. Name string
  4. PathMap string `mapstructure:"path_map"`
  5. }
  6.  
  7. var C config
  8.  
  9. err := Unmarshal(&C)
  10. if err != nil {
  11. t.Fatalf("unable to decode into struct, %v", err)
  12. }

Marshalling to string

You may need to marhsal all the settings held in viper into a string rather than write them to a file.You can use your favorite format's marshaller with the config returned by AllSettings().

  1. import (
  2. yaml "gopkg.in/yaml.v2"
  3. // ...
  4. )
  5.  
  6. func yamlStringSettings() string {
  7. c := viper.AllSettings()
  8. bs, err := yaml.Marshal(c)
  9. if err != nil {
  10. t.Fatalf("unable to marshal config to YAML: %v", err)
  11. }
  12. return string(bs)
  13. }