github.com/hidevopsio/viper@v1.2.2-0.20210220025633-ccb4b202d169/README.md (about) 1 > ## Viper v2 feedback 2 > Viper is heading towards v2 and we would love to hear what _**you**_ would like to see in it. Share your thoughts here: https://forms.gle/R6faU74qPRPAzchZ9 3 > 4 > **Thank you!** 5 6 ![Viper](.github/logo.png?raw=true) 7 8 [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#configuration) 9 [![run on repl.it](https://repl.it/badge/github/sagikazarmark/Viper-example)](https://repl.it/@sagikazarmark/Viper-example#main.go) 10 11 [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/spf13/viper/CI?style=flat-square)](https://github.com/hidevopsio/viper/actions?query=workflow%3ACI) 12 [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 13 [![Go Report Card](https://goreportcard.com/badge/github.com/hidevopsio/viper?style=flat-square)](https://goreportcard.com/report/github.com/hidevopsio/viper) 14 ![Go Version](https://img.shields.io/badge/go%20version-%3E=1.14-61CFDD.svg?style=flat-square) 15 [![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/hidevopsio/viper)](https://pkg.go.dev/mod/github.com/hidevopsio/viper) 16 17 **Go configuration with fangs!** 18 19 Many Go projects are built using Viper including: 20 21 * [Hugo](http://gohugo.io) 22 * [EMC RexRay](http://rexray.readthedocs.org/en/stable/) 23 * [Imgur’s Incus](https://github.com/Imgur/incus) 24 * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) 25 * [Docker Notary](https://github.com/docker/Notary) 26 * [BloomApi](https://www.bloomapi.com/) 27 * [doctl](https://github.com/digitalocean/doctl) 28 * [Clairctl](https://github.com/jgsqware/clairctl) 29 * [Mercure](https://mercure.rocks) 30 31 32 ## Install 33 34 ```shell 35 go get github.com/hidevopsio/viper 36 ``` 37 38 **Note:** Viper uses [Go Modules](https://github.com/golang/go/wiki/Modules) to manage dependencies. 39 40 41 ## What is Viper? 42 43 Viper is a complete configuration solution for Go applications including 12-Factor apps. It is designed 44 to work within an application, and can handle all types of configuration needs 45 and formats. It supports: 46 47 * setting defaults 48 * reading from JSON, TOML, YAML, HCL, envfile and Java properties config files 49 * live watching and re-reading of config files (optional) 50 * reading from environment variables 51 * reading from remote config systems (etcd or Consul), and watching changes 52 * reading from command line flags 53 * reading from buffer 54 * setting explicit values 55 56 Viper can be thought of as a registry for all of your applications configuration needs. 57 58 59 ## Why Viper? 60 61 When building a modern application, you don’t want to worry about 62 configuration file formats; you want to focus on building awesome software. 63 Viper is here to help with that. 64 65 Viper does the following for you: 66 67 1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, INI, envfile or Java properties formats. 68 2. Provide a mechanism to set default values for your different configuration options. 69 3. Provide a mechanism to set override values for options specified through command line flags. 70 4. Provide an alias system to easily rename parameters without breaking existing code. 71 5. Make it easy to tell the difference between when a user has provided a command line or config file which is the same as the default. 72 73 Viper uses the following precedence order. Each item takes precedence over the item below it: 74 75 * explicit call to `Set` 76 * flag 77 * env 78 * config 79 * key/value store 80 * default 81 82 **Important:** Viper configuration keys are case insensitive. 83 There are ongoing discussions about making that optional. 84 85 86 ## Putting Values into Viper 87 88 ### Establishing Defaults 89 90 A good configuration system will support default values. A default value is not 91 required for a key, but it’s useful in the event that a key hasn't been set via 92 config file, environment variable, remote configuration or flag. 93 94 Examples: 95 96 ```go 97 viper.SetDefault("ContentDir", "content") 98 viper.SetDefault("LayoutDir", "layouts") 99 viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"}) 100 ``` 101 102 ### Reading Config Files 103 104 Viper requires minimal configuration so it knows where to look for config files. 105 Viper supports JSON, TOML, YAML, HCL, INI, envfile and Java Properties files. Viper can search multiple paths, but 106 currently a single Viper instance only supports a single configuration file. 107 Viper does not default to any configuration search paths leaving defaults decision 108 to an application. 109 110 Here is an example of how to use Viper to search for and read a configuration file. 111 None of the specific paths are required, but at least one path should be provided 112 where a configuration file is expected. 113 114 ```go 115 viper.SetConfigName("config") // name of config file (without extension) 116 viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name 117 viper.AddConfigPath("/etc/appname/") // path to look for the config file in 118 viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search paths 119 viper.AddConfigPath(".") // optionally look for config in the working directory 120 err := viper.ReadInConfig() // Find and read the config file 121 if err != nil { // Handle errors reading the config file 122 panic(fmt.Errorf("Fatal error config file: %s \n", err)) 123 } 124 ``` 125 126 You can handle the specific case where no config file is found like this: 127 128 ```go 129 if err := viper.ReadInConfig(); err != nil { 130 if _, ok := err.(viper.ConfigFileNotFoundError); ok { 131 // Config file not found; ignore error if desired 132 } else { 133 // Config file was found but another error was produced 134 } 135 } 136 137 // Config file found and successfully parsed 138 ``` 139 140 *NOTE [since 1.6]:* You can also have a file without an extension and specify the format programmaticaly. For those configuration files that lie in the home of the user without any extension like `.bashrc` 141 142 ### Writing Config Files 143 144 Reading from config files is useful, but at times you want to store all modifications made at run time. 145 For that, a bunch of commands are available, each with its own purpose: 146 147 * WriteConfig - writes the current viper configuration to the predefined path, if exists. Errors if no predefined path. Will overwrite the current config file, if it exists. 148 * SafeWriteConfig - writes the current viper configuration to the predefined path. Errors if no predefined path. Will not overwrite the current config file, if it exists. 149 * WriteConfigAs - writes the current viper configuration to the given filepath. Will overwrite the given file, if it exists. 150 * SafeWriteConfigAs - writes the current viper configuration to the given filepath. Will not overwrite the given file, if it exists. 151 152 As a rule of the thumb, everything marked with safe won't overwrite any file, but just create if not existent, whilst the default behavior is to create or truncate. 153 154 A small examples section: 155 156 ```go 157 viper.WriteConfig() // writes current config to predefined path set by 'viper.AddConfigPath()' and 'viper.SetConfigName' 158 viper.SafeWriteConfig() 159 viper.WriteConfigAs("/path/to/my/.config") 160 viper.SafeWriteConfigAs("/path/to/my/.config") // will error since it has already been written 161 viper.SafeWriteConfigAs("/path/to/my/.other_config") 162 ``` 163 164 ### Watching and re-reading config files 165 166 Viper supports the ability to have your application live read a config file while running. 167 168 Gone are the days of needing to restart a server to have a config take effect, 169 viper powered applications can read an update to a config file while running and 170 not miss a beat. 171 172 Simply tell the viper instance to watchConfig. 173 Optionally you can provide a function for Viper to run each time a change occurs. 174 175 **Make sure you add all of the configPaths prior to calling `WatchConfig()`** 176 177 ```go 178 viper.WatchConfig() 179 viper.OnConfigChange(func(e fsnotify.Event) { 180 fmt.Println("Config file changed:", e.Name) 181 }) 182 ``` 183 184 ### Reading Config from io.Reader 185 186 Viper predefines many configuration sources such as files, environment 187 variables, flags, and remote K/V store, but you are not bound to them. You can 188 also implement your own required configuration source and feed it to viper. 189 190 ```go 191 viper.SetConfigType("yaml") // or viper.SetConfigType("YAML") 192 193 // any approach to require this configuration into your program. 194 var yamlExample = []byte(` 195 Hacker: true 196 name: steve 197 hobbies: 198 - skateboarding 199 - snowboarding 200 - go 201 clothing: 202 jacket: leather 203 trousers: denim 204 age: 35 205 eyes : brown 206 beard: true 207 `) 208 209 viper.ReadConfig(bytes.NewBuffer(yamlExample)) 210 211 viper.Get("name") // this would be "steve" 212 ``` 213 214 ### Setting Overrides 215 216 These could be from a command line flag, or from your own application logic. 217 218 ```go 219 viper.Set("Verbose", true) 220 viper.Set("LogFile", LogFile) 221 ``` 222 223 ### Registering and Using Aliases 224 225 Aliases permit a single value to be referenced by multiple keys 226 227 ```go 228 viper.RegisterAlias("loud", "Verbose") 229 230 viper.Set("verbose", true) // same result as next line 231 viper.Set("loud", true) // same result as prior line 232 233 viper.GetBool("loud") // true 234 viper.GetBool("verbose") // true 235 ``` 236 237 ### Working with Environment Variables 238 239 Viper has full support for environment variables. This enables 12 factor 240 applications out of the box. There are five methods that exist to aid working 241 with ENV: 242 243 * `AutomaticEnv()` 244 * `BindEnv(string...) : error` 245 * `SetEnvPrefix(string)` 246 * `SetEnvKeyReplacer(string...) *strings.Replacer` 247 * `AllowEmptyEnv(bool)` 248 249 _When working with ENV variables, it’s important to recognize that Viper 250 treats ENV variables as case sensitive._ 251 252 Viper provides a mechanism to try to ensure that ENV variables are unique. By 253 using `SetEnvPrefix`, you can tell Viper to use a prefix while reading from 254 the environment variables. Both `BindEnv` and `AutomaticEnv` will use this 255 prefix. 256 257 `BindEnv` takes one or more parameters. The first parameter is the key name, the 258 rest are the name of the environment variables to bind to this key. If more than 259 one are provided, they will take precedence in the specified order. The name of 260 the environment variable is case sensitive. If the ENV variable name is not provided, then 261 Viper will automatically assume that the ENV variable matches the following format: prefix + "_" + the key name in ALL CAPS. When you explicitly provide the ENV variable name (the second parameter), 262 it **does not** automatically add the prefix. For example if the second parameter is "id", 263 Viper will look for the ENV variable "ID". 264 265 One important thing to recognize when working with ENV variables is that the 266 value will be read each time it is accessed. Viper does not fix the value when 267 the `BindEnv` is called. 268 269 `AutomaticEnv` is a powerful helper especially when combined with 270 `SetEnvPrefix`. When called, Viper will check for an environment variable any 271 time a `viper.Get` request is made. It will apply the following rules. It will 272 check for an environment variable with a name matching the key uppercased and 273 prefixed with the `EnvPrefix` if set. 274 275 `SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env 276 keys to an extent. This is useful if you want to use `-` or something in your 277 `Get()` calls, but want your environmental variables to use `_` delimiters. An 278 example of using it can be found in `viper_test.go`. 279 280 Alternatively, you can use `EnvKeyReplacer` with `NewWithOptions` factory function. 281 Unlike `SetEnvKeyReplacer`, it accepts a `StringReplacer` interface allowing you to write custom string replacing logic. 282 283 By default empty environment variables are considered unset and will fall back to 284 the next configuration source. To treat empty environment variables as set, use 285 the `AllowEmptyEnv` method. 286 287 #### Env example 288 289 ```go 290 SetEnvPrefix("spf") // will be uppercased automatically 291 BindEnv("id") 292 293 os.Setenv("SPF_ID", "13") // typically done outside of the app 294 295 id := Get("id") // 13 296 ``` 297 298 ### Working with Flags 299 300 Viper has the ability to bind to flags. Specifically, Viper supports `Pflags` 301 as used in the [Cobra](https://github.com/spf13/cobra) library. 302 303 Like `BindEnv`, the value is not set when the binding method is called, but when 304 it is accessed. This means you can bind as early as you want, even in an 305 `init()` function. 306 307 For individual flags, the `BindPFlag()` method provides this functionality. 308 309 Example: 310 311 ```go 312 serverCmd.Flags().Int("port", 1138, "Port to run Application server on") 313 viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) 314 ``` 315 316 You can also bind an existing set of pflags (pflag.FlagSet): 317 318 Example: 319 320 ```go 321 pflag.Int("flagname", 1234, "help message for flagname") 322 323 pflag.Parse() 324 viper.BindPFlags(pflag.CommandLine) 325 326 i := viper.GetInt("flagname") // retrieve values from viper instead of pflag 327 ``` 328 329 The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude 330 the use of other packages that use the [flag](https://golang.org/pkg/flag/) 331 package from the standard library. The pflag package can handle the flags 332 defined for the flag package by importing these flags. This is accomplished 333 by a calling a convenience function provided by the pflag package called 334 AddGoFlagSet(). 335 336 Example: 337 338 ```go 339 package main 340 341 import ( 342 "flag" 343 "github.com/spf13/pflag" 344 ) 345 346 func main() { 347 348 // using standard library "flag" package 349 flag.Int("flagname", 1234, "help message for flagname") 350 351 pflag.CommandLine.AddGoFlagSet(flag.CommandLine) 352 pflag.Parse() 353 viper.BindPFlags(pflag.CommandLine) 354 355 i := viper.GetInt("flagname") // retrieve value from viper 356 357 ... 358 } 359 ``` 360 361 #### Flag interfaces 362 363 Viper provides two Go interfaces to bind other flag systems if you don’t use `Pflags`. 364 365 `FlagValue` represents a single flag. This is a very simple example on how to implement this interface: 366 367 ```go 368 type myFlag struct {} 369 func (f myFlag) HasChanged() bool { return false } 370 func (f myFlag) Name() string { return "my-flag-name" } 371 func (f myFlag) ValueString() string { return "my-flag-value" } 372 func (f myFlag) ValueType() string { return "string" } 373 ``` 374 375 Once your flag implements this interface, you can simply tell Viper to bind it: 376 377 ```go 378 viper.BindFlagValue("my-flag-name", myFlag{}) 379 ``` 380 381 `FlagValueSet` represents a group of flags. This is a very simple example on how to implement this interface: 382 383 ```go 384 type myFlagSet struct { 385 flags []myFlag 386 } 387 388 func (f myFlagSet) VisitAll(fn func(FlagValue)) { 389 for _, flag := range flags { 390 fn(flag) 391 } 392 } 393 ``` 394 395 Once your flag set implements this interface, you can simply tell Viper to bind it: 396 397 ```go 398 fSet := myFlagSet{ 399 flags: []myFlag{myFlag{}, myFlag{}}, 400 } 401 viper.BindFlagValues("my-flags", fSet) 402 ``` 403 404 ### Remote Key/Value Store Support 405 406 To enable remote support in Viper, do a blank import of the `viper/remote` 407 package: 408 409 `import _ "github.com/hidevopsio/viper/remote"` 410 411 Viper will read a config string (as JSON, TOML, YAML, HCL or envfile) retrieved from a path 412 in a Key/Value store such as etcd or Consul. These values take precedence over 413 default values, but are overridden by configuration values retrieved from disk, 414 flags, or environment variables. 415 416 Viper uses [crypt](https://github.com/bketelsen/crypt) to retrieve 417 configuration from the K/V store, which means that you can store your 418 configuration values encrypted and have them automatically decrypted if you have 419 the correct gpg keyring. Encryption is optional. 420 421 You can use remote configuration in conjunction with local configuration, or 422 independently of it. 423 424 `crypt` has a command-line helper that you can use to put configurations in your 425 K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001. 426 427 ```bash 428 $ go get github.com/bketelsen/crypt/bin/crypt 429 $ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json 430 ``` 431 432 Confirm that your value was set: 433 434 ```bash 435 $ crypt get -plaintext /config/hugo.json 436 ``` 437 438 See the `crypt` documentation for examples of how to set encrypted values, or 439 how to use Consul. 440 441 ### Remote Key/Value Store Example - Unencrypted 442 443 #### etcd 444 ```go 445 viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json") 446 viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" 447 err := viper.ReadRemoteConfig() 448 ``` 449 450 #### Consul 451 You need to set a key to Consul key/value storage with JSON value containing your desired config. 452 For example, create a Consul key/value store key `MY_CONSUL_KEY` with value: 453 454 ```json 455 { 456 "port": 8080, 457 "hostname": "myhostname.com" 458 } 459 ``` 460 461 ```go 462 viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY") 463 viper.SetConfigType("json") // Need to explicitly set this to json 464 err := viper.ReadRemoteConfig() 465 466 fmt.Println(viper.Get("port")) // 8080 467 fmt.Println(viper.Get("hostname")) // myhostname.com 468 ``` 469 470 #### Firestore 471 472 ```go 473 viper.AddRemoteProvider("firestore", "google-cloud-project-id", "collection/document") 474 viper.SetConfigType("json") // Config's format: "json", "toml", "yaml", "yml" 475 err := viper.ReadRemoteConfig() 476 ``` 477 478 Of course, you're allowed to use `SecureRemoteProvider` also 479 480 ### Remote Key/Value Store Example - Encrypted 481 482 ```go 483 viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg") 484 viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" 485 err := viper.ReadRemoteConfig() 486 ``` 487 488 ### Watching Changes in etcd - Unencrypted 489 490 ```go 491 // alternatively, you can create a new viper instance. 492 var runtime_viper = viper.New() 493 494 runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml") 495 runtime_viper.SetConfigType("yaml") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv" 496 497 // read from remote config the first time. 498 err := runtime_viper.ReadRemoteConfig() 499 500 // unmarshal config 501 runtime_viper.Unmarshal(&runtime_conf) 502 503 // open a goroutine to watch remote changes forever 504 go func(){ 505 for { 506 time.Sleep(time.Second * 5) // delay after each request 507 508 // currently, only tested with etcd support 509 err := runtime_viper.WatchRemoteConfig() 510 if err != nil { 511 log.Errorf("unable to read remote config: %v", err) 512 continue 513 } 514 515 // unmarshal new config into our runtime config struct. you can also use channel 516 // to implement a signal to notify the system of the changes 517 runtime_viper.Unmarshal(&runtime_conf) 518 } 519 }() 520 ``` 521 522 ## Getting Values From Viper 523 524 In Viper, there are a few ways to get a value depending on the value’s type. 525 The following functions and methods exist: 526 527 * `Get(key string) : interface{}` 528 * `GetBool(key string) : bool` 529 * `GetFloat64(key string) : float64` 530 * `GetInt(key string) : int` 531 * `GetIntSlice(key string) : []int` 532 * `GetString(key string) : string` 533 * `GetStringMap(key string) : map[string]interface{}` 534 * `GetStringMapString(key string) : map[string]string` 535 * `GetStringSlice(key string) : []string` 536 * `GetTime(key string) : time.Time` 537 * `GetDuration(key string) : time.Duration` 538 * `IsSet(key string) : bool` 539 * `AllSettings() : map[string]interface{}` 540 541 One important thing to recognize is that each Get function will return a zero 542 value if it’s not found. To check if a given key exists, the `IsSet()` method 543 has been provided. 544 545 Example: 546 ```go 547 viper.GetString("logfile") // case-insensitive Setting & Getting 548 if viper.GetBool("verbose") { 549 fmt.Println("verbose enabled") 550 } 551 ``` 552 ### Accessing nested keys 553 554 The accessor methods also accept formatted paths to deeply nested keys. For 555 example, if the following JSON file is loaded: 556 557 ```json 558 { 559 "host": { 560 "address": "localhost", 561 "port": 5799 562 }, 563 "datastore": { 564 "metric": { 565 "host": "127.0.0.1", 566 "port": 3099 567 }, 568 "warehouse": { 569 "host": "198.0.0.1", 570 "port": 2112 571 } 572 } 573 } 574 575 ``` 576 577 Viper can access a nested field by passing a `.` delimited path of keys: 578 579 ```go 580 GetString("datastore.metric.host") // (returns "127.0.0.1") 581 ``` 582 583 This obeys the precedence rules established above; the search for the path 584 will cascade through the remaining configuration registries until found. 585 586 For example, given this configuration file, both `datastore.metric.host` and 587 `datastore.metric.port` are already defined (and may be overridden). If in addition 588 `datastore.metric.protocol` was defined in the defaults, Viper would also find it. 589 590 However, if `datastore.metric` was overridden (by a flag, an environment variable, 591 the `Set()` method, …) with an immediate value, then all sub-keys of 592 `datastore.metric` become undefined, they are “shadowed” by the higher-priority 593 configuration level. 594 595 Viper can access array indices by using numbers in the path. For example: 596 597 ```json 598 { 599 "host": { 600 "address": "localhost", 601 "ports": [ 602 5799, 603 6029 604 ] 605 }, 606 "datastore": { 607 "metric": { 608 "host": "127.0.0.1", 609 "port": 3099 610 }, 611 "warehouse": { 612 "host": "198.0.0.1", 613 "port": 2112 614 } 615 } 616 } 617 618 GetInt("host.ports.1") // returns 6029 619 620 ``` 621 622 Lastly, if there exists a key that matches the delimited key path, its value 623 will be returned instead. E.g. 624 625 ```json 626 { 627 "datastore.metric.host": "0.0.0.0", 628 "host": { 629 "address": "localhost", 630 "port": 5799 631 }, 632 "datastore": { 633 "metric": { 634 "host": "127.0.0.1", 635 "port": 3099 636 }, 637 "warehouse": { 638 "host": "198.0.0.1", 639 "port": 2112 640 } 641 } 642 } 643 644 GetString("datastore.metric.host") // returns "0.0.0.0" 645 ``` 646 647 ### Extracting a sub-tree 648 649 When developing reusable modules, it's often useful to extract a subset of the configuration 650 and pass it to a module. This way the module can be instantiated more than once, with different configurations. 651 652 For example, an application might use multiple different cache stores for different purposes: 653 654 ```yaml 655 cache: 656 cache1: 657 max-items: 100 658 item-size: 64 659 cache2: 660 max-items: 200 661 item-size: 80 662 ``` 663 664 We could pass the cache name to a module (eg. `NewCache("cache1")`), 665 but it would require weird concatenation for accessing config keys and would be less separated from the global config. 666 667 So instead of doing that let's pass a Viper instance to the constructor that represents a subset of the configuration: 668 669 ```go 670 cache1Config := viper.Sub("cache.cache1") 671 if cache1Config == nil { // Sub returns nil if the key cannot be found 672 panic("cache configuration not found") 673 } 674 675 cache1 := NewCache(cache1Config) 676 ``` 677 678 **Note:** Always check the return value of `Sub`. It returns `nil` if a key cannot be found. 679 680 Internally, the `NewCache` function can address `max-items` and `item-size` keys directly: 681 682 ```go 683 func NewCache(v *Viper) *Cache { 684 return &Cache{ 685 MaxItems: v.GetInt("max-items"), 686 ItemSize: v.GetInt("item-size"), 687 } 688 } 689 ``` 690 691 The resulting code is easy to test, since it's decoupled from the main config structure, 692 and easier to reuse (for the same reason). 693 694 695 ### Unmarshaling 696 697 You also have the option of Unmarshaling all or a specific value to a struct, map, 698 etc. 699 700 There are two methods to do this: 701 702 * `Unmarshal(rawVal interface{}) : error` 703 * `UnmarshalKey(key string, rawVal interface{}) : error` 704 705 Example: 706 707 ```go 708 type config struct { 709 Port int 710 Name string 711 PathMap string `mapstructure:"path_map"` 712 } 713 714 var C config 715 716 err := viper.Unmarshal(&C) 717 if err != nil { 718 t.Fatalf("unable to decode into struct, %v", err) 719 } 720 ``` 721 722 If you want to unmarshal configuration where the keys themselves contain dot (the default key delimiter), 723 you have to change the delimiter: 724 725 ```go 726 v := viper.NewWithOptions(viper.KeyDelimiter("::")) 727 728 v.SetDefault("chart::values", map[string]interface{}{ 729 "ingress": map[string]interface{}{ 730 "annotations": map[string]interface{}{ 731 "traefik.frontend.rule.type": "PathPrefix", 732 "traefik.ingress.kubernetes.io/ssl-redirect": "true", 733 }, 734 }, 735 }) 736 737 type config struct { 738 Chart struct{ 739 Values map[string]interface{} 740 } 741 } 742 743 var C config 744 745 v.Unmarshal(&C) 746 ``` 747 748 Viper also supports unmarshaling into embedded structs: 749 750 ```go 751 /* 752 Example config: 753 754 module: 755 enabled: true 756 token: 89h3f98hbwf987h3f98wenf89ehf 757 */ 758 type config struct { 759 Module struct { 760 Enabled bool 761 762 moduleConfig `mapstructure:",squash"` 763 } 764 } 765 766 // moduleConfig could be in a module specific package 767 type moduleConfig struct { 768 Token string 769 } 770 771 var C config 772 773 err := viper.Unmarshal(&C) 774 if err != nil { 775 t.Fatalf("unable to decode into struct, %v", err) 776 } 777 ``` 778 779 Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default. 780 781 ### Marshalling to string 782 783 You may need to marshal all the settings held in viper into a string rather than write them to a file. 784 You can use your favorite format's marshaller with the config returned by `AllSettings()`. 785 786 ```go 787 import ( 788 yaml "gopkg.in/yaml.v2" 789 // ... 790 ) 791 792 func yamlStringSettings() string { 793 c := viper.AllSettings() 794 bs, err := yaml.Marshal(c) 795 if err != nil { 796 log.Fatalf("unable to marshal config to YAML: %v", err) 797 } 798 return string(bs) 799 } 800 ``` 801 802 ## Viper or Vipers? 803 804 Viper comes ready to use out of the box. There is no configuration or 805 initialization needed to begin using Viper. Since most applications will want 806 to use a single central repository for their configuration, the viper package 807 provides this. It is similar to a singleton. 808 809 In all of the examples above, they demonstrate using viper in its singleton 810 style approach. 811 812 ### Working with multiple vipers 813 814 You can also create many different vipers for use in your application. Each will 815 have its own unique set of configurations and values. Each can read from a 816 different config file, key value store, etc. All of the functions that viper 817 package supports are mirrored as methods on a viper. 818 819 Example: 820 821 ```go 822 x := viper.New() 823 y := viper.New() 824 825 x.SetDefault("ContentDir", "content") 826 y.SetDefault("ContentDir", "foobar") 827 828 //... 829 ``` 830 831 When working with multiple vipers, it is up to the user to keep track of the 832 different vipers. 833 834 835 ## Q & A 836 837 ### Why is it called “Viper”? 838 839 A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe)) 840 to [Cobra](https://github.com/spf13/cobra). While both can operate completely 841 independently, together they make a powerful pair to handle much of your 842 application foundation needs. 843 844 ### Why is it called “Cobra”? 845 846 Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)? 847 848 ### Does Viper support case sensitive keys? 849 850 **tl;dr:** No. 851 852 Viper merges configuration from various sources, many of which are either case insensitive or uses different casing than the rest of the sources (eg. env vars). 853 In order to provide the best experience when using multiple sources, the decision has been made to make all keys case insensitive. 854 855 There has been several attempts to implement case sensitivity, but unfortunately it's not that trivial. We might take a stab at implementing it in [Viper v2](https://github.com/hidevopsio/viper/issues/772), but despite the initial noise, it does not seem to be requested that much. 856 857 You can vote for case sensitivity by filling out this feedback form: https://forms.gle/R6faU74qPRPAzchZ9 858 859 860 ## Troubleshooting 861 862 See [TROUBLESHOOTING.md](TROUBLESHOOTING.md).