Golang Viper – load multiple configuration files

In a previous post, I covered on basic usage of the Golang library Viper. As of version v1.14.0, a single Viper instance supports loading configurations from only one configuration file. If our application work with multiple configuration files, then we have to manage this manually. This post covers how to load configurations from multiple configuration files using Viper in Golang.

The idea

The idea is fairly simple. Since one Viper instance can load configurations from only one configuration file, we will have multiple Viper instances loaded with configurations from multiple files. To access these instances easily, we will store all the Viper instances into a global map against their configuration name. Finally to fetch value of a config key, we will expose a function that would fetch the Viper instance from the map and then return the value from the instance.

Load from multiple configuration files

Let’s see with some examples. I will be using the same project that I created in my previous post to cover the examples. Here is the Github repo of the full project.

In the example project, I have three .yml files under resources package. Now, I will be loading the configurations from these files. In order to achieve this, I created a new config.go file under config package. As per our idea, I added logic to do the below.

  • Firstly, to have a local map to store multiple instances of Viper per configuration
  • Then, to load the configurations into the local map
  • Finally, to retrieve the config property by the config file

Below is the entire code.

package config

import (
    "fmt"

    "github.com/spf13/viper"
)

const (
    App      string = "app"
    Database string = "database"
    External string = "external"
)

var configMap map[string]*viper.Viper

func init() {
    configMap = make(map[string]*viper.Viper)
}

func LoadConfigs(configs ...string) {
    for _, configName := range configs {
        viperInstance := viper.New()
        viperInstance.SetConfigName(configName)
        viperInstance.SetConfigType("yaml")
        viperInstance.AddConfigPath("./resources")
        err := viperInstance.ReadInConfig()
        if err != nil {
            panic(fmt.Errorf("fatal error config file: %s %w", configName, err))
        }
        configMap[configName] = viperInstance
    }
}

func GetByConfig(configName, key string) interface{} {
    instance, ok := configMap[configName]
    if !ok {
        return nil
    }
    return instance.Get(key)
}

In the code, I have a global private map variable configMap which stores Viper instances against the config name. When the method LoadConfigs is invoked with list of configurations to be loaded, it creates a new Viper instance against each configuration name and puts them in the map. For simplicity, I’m having the config name same as the .yml file name. Finally, we have the GetByConfig method which takes both config name and config key as inputs. It fetches the Viper instance using the config name and then returns the value corresponding to the key passed.

Testing the example

To test this, I have created below methods.

func init() {
	config.LoadConfigs(config.App, config.Database, config.External)
}

func RunMultipleConfig() {
    printConfig(config.App, "application.name")
    printConfig(config.Database, "database.host")
    printConfig(config.External, "external.http.getEmployee.url")
}

func printConfig(configName, key string) {
    fmt.Printf("value of '%s' from config '%s' is '%s'\n", key, configName, config.GetByConfig(configName, key))
}

As the initial step, on execution, the init method will load all the three app, database and external configurations into the map. Now when I invoke the function RunMultipleConfig, each line in the function will fetch and print values from different configuration files. Below is the output of the program.

value of 'application.name' from config 'app' is 'thegeeksclan'
value of 'database.host' from config 'database' is 'localhost'
value of 'external.http.getEmployee.url' from config 'external' is 'https://dummy.restapiexample.com/api/v1/employees'

Conclusion

With this, we have reached the end of our post. This is a simple approach to load configurations from multiple configuration files using Viper. Don’t miss the other posts below related to Viper. Stay tuned for more such content.


I hope this post was helpful 😊. If you find this post informative, support us by sharing this with fellow programmers in your circle 😀.

For any suggestions, improvements, reviews or if you like us to cover a specific topic, please leave a comment.
Follow us on twitter @thegeeksclan and in Facebook.
#TheGeeksClan #DevCommunity

2 thoughts on “Golang Viper – load multiple configuration files”

  1. Pingback: Using Viper with environment variables in Golang - The Geeks Clan

  2. Pingback: Loading configurations using Viper in Golang - The Geeks Clan

Comments are closed.

error

Enjoy this blog? Please spread the word :)