diff --git a/README.md b/README.md index 23702fd..47b1798 100644 --- a/README.md +++ b/README.md @@ -7,41 +7,41 @@ Go configuration with fangs ## What is Viper? -Viper is a complete configuration solution for go applications. It has -been designed to work within an application to handle all types of -configuration. It supports +Viper is a complete configuration solution for go applications. It is designed +to work within an application, and can handle all types of configuration needs +and formats. It supports: * setting defaults -* reading from json, toml and yaml config files +* reading from JSON, TOML, and YAML config files * reading from environment variables -* reading from remote config systems (Etcd or Consul), watching changes +* reading from remote config systems (Etcd or Consul), and watching changes * reading from command line flags * reading from buffer * setting explicit values -It can be thought of as a registry for all of your applications +Viper can be thought of as a registry for all of your applications configuration needs. ## Why Viper? -When building a modern application, you don’t want to have to worry about +When building a modern application, you don’t want to worry about configuration file formats; you want to focus on building awesome software. Viper is here to help with that. Viper does the following for you: -1. Find, load and marshal a configuration file in JSON, TOML or YAML. +1. Find, load, and marshal a configuration file in JSON, TOML, or YAML. 2. Provide a mechanism to set default values for your different configuration options. -3. Provide a mechanism to set override values for options specified - through command line flags. -4. Provide an alias system to easily rename parameters without breaking - existing code. -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. +3. Provide a mechanism to set override values for options specified through + command line flags. +4. Provide an alias system to easily rename parameters without breaking existing + code. +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. -Viper uses the following precedence order. Each item takes precedence -over the item below it: +Viper uses the following precedence order. Each item takes precedence over the +item below it: * explicit call to Set * flag @@ -56,10 +56,9 @@ Viper configuration keys are case insensitive. ### Establishing Defaults -A good configuration system will support default values. A default value -is not required for a key, but can establish a default to be used in the -event that the key hasn’t be set via config file, environment variable, -remote configuration or flag. +A good configuration system will support default values. A default value is not +required for a key, but it's useful in the event that a key hasn’t be set via +config file, environment variable, remote configuration or flag. Examples: @@ -71,10 +70,9 @@ viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "cat ### Reading Config Files -If you want to support a config file, Viper requires a minimal -configuration so it knows where to look for the config file. Viper -supports json, toml and yaml files. Viper can search multiple paths, but -currently a single viper only supports a single config file. +Viper requires minimal configuration so it knows where to look for config files. +Viper supports JSON, TOML and YAML files. Viper can search multiple paths, but +currently a single Viper instance only supports a single configuration file. ```go viper.SetConfigName("config") // name of config file (without extension) @@ -88,14 +86,14 @@ if err != nil { // Handle errors reading the config file ### Reading Config from io.Reader -Viper predefined many configuration sources, such as files, environment variables, flags and -remote K/V store. But you are not bound to them. You can also implement your own way to -require configuration and feed it to viper. +Viper predefines many configuration sources such as files, environment +variables, flags, and remote K/V store, but you are not bound to them. You can +also implement your own required configuration source and feed it to viper. ```go viper.SetConfigType("yaml") // or viper.SetConfigType("YAML") -// any approach to require this configuration into your program. +// any approach to require this configuration into your program. var yamlExample = []byte(` Hacker: true name: steve @@ -142,44 +140,43 @@ viper.GetBool("verbose") // true ### Working with Environment Variables Viper has full support for environment variables. This enables 12 factor -applications out of the box. There are four methods that exist to aid -with working with ENV: +applications out of the box. There are four methods that exist to aid working +with ENV: - * AutomaticEnv() - * BindEnv(string...) : error - * SetEnvPrefix(string) - * SetEnvReplacer(string...) *strings.Replacer + * `AutomaticEnv()` + * `BindEnv(string...) : error` + * `SetEnvPrefix(string)` + * `SetEnvReplacer(string...) *strings.Replacer` _When working with ENV variables, it’s important to recognize that Viper treats ENV variables as case sensitive._ -Viper provides a mechanism to try to ensure that ENV variables are -unique. By using SetEnvPrefix, you can tell Viper to use add a prefix -while reading from the environment variables. Both BindEnv and -AutomaticEnv will use this prefix. +Viper provides a mechanism to try to ensure that ENV variables are unique. By +using `SetEnvPrefix`, you can tell Viper to use add a prefix while reading from +the environment variables. Both `BindEnv` and `AutomaticEnv` will use this +prefix. -BindEnv takes one or two parameters. The first parameter is the key -name, the second is the name of the environment variable. The name of -the environment variable is case sensitive. If the ENV variable name is -not provided, then Viper will automatically assume that the key name -matches the ENV variable name but the ENV variable is IN ALL CAPS. When -you explicitly provide the ENV variable name, it **does not** -automatically add the prefix. +`BindEnv` takes one or two parameters. The first parameter is the key name, the +second is the name of the environment variable. The name of the environment +variable is case sensitive. If the ENV variable name is not provided, then +Viper will automatically assume that the key name matches the ENV variable name, +but the ENV variable is IN ALL CAPS. When you explicitly provide the ENV +variable name, it **does not** automatically add the prefix. -One important thing to recognize when working with ENV variables is that -the value will be read each time it is accessed. It does not fix the -value when the BindEnv is called. +One important thing to recognize when working with ENV variables is that the +value will be read each time it is accessed. Viper does not fix the value when +the `BindEnv` is called. -AutomaticEnv is a powerful helper especially when combined with -SetEnvPrefix. When called, Viper will check for an environment variable -any time a viper.Get request is made. It will apply the following rules. -It will check for a environment variable with a name matching the key -uppercased and prefixed with the EnvPrefix if set. +`AutomaticEnv` is a powerful helper especially when combined with +`SetEnvPrefix`. When called, Viper will check for an environment variable any +time a `viper.Get` request is made. It will apply the following rules. It will +check for a environment variable with a name matching the key uppercased and +prefixed with the `EnvPrefix` if set. -SetEnvReplacer allows you to use a `strings.Replacer` object to rewrite Env keys -to an extent. This is useful if you want to use `-` or something in your Get() -calls, but want your environmental variables to use `_` delimiters. An example -of using it can be found in `viper_test.go`. +`SetEnvReplacer` allows you to use a `strings.Replacer` object to rewrite Env +keys to an extent. This is useful if you want to use `-` or something in your +`Get()` calls, but want your environmental variables to use `_` delimiters. An +example of using it can be found in `viper_test.go`. #### Env example @@ -194,14 +191,14 @@ id := Get("id") // 13 ### Working with Flags -Viper has the ability to bind to flags. Specifically, Viper supports -Pflags as used in the [Cobra](https://github.com/spf13/cobra) library. +Viper has the ability to bind to flags. Specifically, Viper supports `Pflags` +as used in the [Cobra](https://github.com/spf13/cobra) library. -Like BindEnv, the value is not set when the binding method is called, but -when it is accessed. This means you can bind as early as you want, even -in an init() function. +Like `BindEnv`, the value is not set when the binding method is called, but when +it is accessed. This means you can bind as early as you want, even in an +`init()` function. -The BindPFlag() method provides this functionality. +The `BindPFlag()` method provides this functionality. Example: @@ -212,25 +209,26 @@ viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) ### Remote Key/Value Store Support -To enable remote support in Viper, do a blank import of the `viper/remote` package: +To enable remote support in Viper, do a blank import of the `viper/remote` +package: `import _ github.com/spf13/viper/remote` -Viper will read a config string (as JSON, TOML, or YAML) retrieved from a -path in a Key/Value store such as Etcd or Consul. These values take precedence -over default values, but are overriden by configuration values retrieved from disk, +Viper will read a config string (as JSON, TOML, or YAML) retrieved from a path +in a Key/Value store such as Etcd or Consul. These values take precedence over +default values, but are overridden by configuration values retrieved from disk, flags, or environment variables. -Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve configuration -from the K/V store, which means that you can store your configuration values -encrypted and have them automatically decrypted if you have the correct -gpg keyring. Encryption is optional. +Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve +configuration from the K/V store, which means that you can store your +configuration values encrypted and have them automatically decrypted if you have +the correct gpg keyring. Encryption is optional. You can use remote configuration in conjunction with local configuration, or independently of it. -`crypt` has a command-line helper that you can use to put configurations -in your K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001. +`crypt` has a command-line helper that you can use to put configurations in your +K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001. ```bash $ go get github.com/xordataexchange/crypt/bin/crypt @@ -243,8 +241,8 @@ Confirm that your value was set: $ crypt get -plaintext /config/hugo.json ``` -See the `crypt` documentation for examples of how to set encrypted values, or how -to use Consul. +See the `crypt` documentation for examples of how to set encrypted values, or +how to use Consul. ### Remote Key/Value Store Example - Unencrypted @@ -298,24 +296,24 @@ go func(){ ## Getting Values From Viper -In Viper, there are a few ways to get a value depending on what type of value you want to retrieved. +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 + * `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` -One important thing to recognize is that each Get function will return -its zero value if it’s not found. To check if a given key exists, the IsSet() -method has been provided. +One important thing to recognize is that each Get function will return a zero +value if it’s not found. To check if a given key exists, the `IsSet()` method +has been provided. Example: ```go @@ -326,8 +324,8 @@ if viper.GetBool("verbose") { ``` ### Accessing nested keys -The accessor methods also accept formatted paths to deeply nested keys. -For example, if the following JSON file is loaded: +The accessor methods also accept formatted paths to deeply nested keys. For +example, if the following JSON file is loaded: ```json { @@ -355,18 +353,19 @@ Viper can access a nested field by passing a `.` delimited path of keys: GetString("datastore.metric.host") // (returns "127.0.0.1") ``` -This obeys the precendense rules established above; the search for the root key -(in this examole, `datastore`) will cascade through the remaining configuration registries -until found. The search for the subkeys (`metric` and `host`), however, will not. +This obeys the precedence rules established above; the search for the root key +(in this example, `datastore`) will cascade through the remaining configuration +registries until found. The search for the sub-keys (`metric` and `host`), +however, will not. For example, if the `metric` key was not defined in the configuration loaded from file, but was defined in the defaults, Viper would return the zero value. -On the other hand, if the primary key was not defined, Viper would go through the -remaining registries looking for it. +On the other hand, if the primary key was not defined, Viper would go through +the remaining registries looking for it. -Lastly, if there exists a key that matches the delimited key path, its value will -be returned instead. E.g. +Lastly, if there exists a key that matches the delimited key path, its value +will be returned instead. E.g. ```json { @@ -392,12 +391,13 @@ GetString("datastore.metric.host") //returns "0.0.0.0" ### Marshaling -You also have the option of Marshaling all or a specific value to a struct, map, etc. +You also have the option of Marshaling all or a specific value to a struct, map, +etc. There are two methods to do this: - * Marshal(rawVal interface{}) : error - * MarshalKey(key string, rawVal interface{}) : error + * `Marshal(rawVal interface{}) : error` + * `MarshalKey(key string, rawVal interface{}) : error` Example: @@ -418,19 +418,19 @@ if err != nil { ## Viper or Vipers? Viper comes ready to use out of the box. There is no configuration or -initialization needed to begin using Viper. Since most applications will -want to use a single central repository for their configuration, the -viper package provides this. It is similar to a singleton. +initialization needed to begin using Viper. Since most applications will want +to use a single central repository for their configuration, the viper package +provides this. It is similar to a singleton. -In all of the examples above, they demonstrate using viper in its -singleton style approach. +In all of the examples above, they demonstrate using viper in it's singleton +style approach. ### Working with multiple vipers -You can also create many different vipers for use in your application. -Each will have it’s own unique set of configurations and values. Each -can read from a different config file, key value store, etc. All of the -functions that viper package supports are mirrored as methods on a viper. +You can also create many different vipers for use in your application. Each will +have it’s own unique set of configurations and values. Each can read from a +different config file, key value store, etc. All of the functions that viper +package supports are mirrored as methods on a viper. Example: @@ -444,8 +444,8 @@ y.SetDefault("ContentDir", "foobar") //... ``` -When working with multiple vipers, it is up to the user to keep track of -the different vipers. +When working with multiple vipers, it is up to the user to keep track of the +different vipers. ## Q & A @@ -453,13 +453,13 @@ Q: Why not INI files? A: Ini files are pretty awful. There’s no standard format, and they are hard to validate. Viper is designed to work with JSON, TOML or YAML files. If someone -really wants to add this feature, I’d be happy to merge it. It’s easy to -specify which formats your application will permit. +really wants to add this feature, I’d be happy to merge it. It’s easy to specify +which formats your application will permit. Q: Why is it called “Viper”? -A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe)) to -[Cobra](https://github.com/spf13/cobra). While both can operate completely +A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe)) +to [Cobra](https://github.com/spf13/cobra). While both can operate completely independently, together they make a powerful pair to handle much of your application foundation needs.