For example, you want to have different settings in development and production environments, or you just have a separate fleets for different clients.
It is pretty easy to add configuration support to you Go application using YAML for configurations and gopkg.in/yaml.v2 for deserializing YAML files into struct value.
Here is an example YAML configuration file. It contains service name and its listening endpoint, and also database connection URL. Pretty simple!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Service name and address to listen | |
service: | |
name: AccountService | |
address: 127.0.0.1:12020 | |
# DBs to connect to, storing password is OK for local DEV database | |
db: | |
accounts: postgres://192.168.99.100:32768/accounts?user=ABC&password=XYZ&sslmode=disable |
To read configuration, we first open and read whole configuration file, and then use yaml package to unmarshal it into value of Configuration type.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "gopkg.in/yaml.v2" | |
// Configuration object that stores all configuration data | |
type Configuration struct { | |
Db DbConfiguration | |
Service ServiceConfiguration | |
} | |
// Database configuration | |
type DbConfiguration struct { | |
Accounts string | |
} | |
// Service configuration | |
type ServiceConfiguration struct { | |
Name string | |
Address string | |
} | |
// LoadConfiguration loads configuration from specified file | |
func LoadConfiguration(configFilePath string) (*Configuration, error) { | |
file, err := os.Open(configFilePath) | |
if err != nil { | |
return nil, fmt.Errorf("failed to load file %s: %s", configFilePath, err) | |
} | |
data, err := ioutil.ReadAll(file) | |
if err != nil { | |
return nil, fmt.Errorf("failed to read file %s: %s", configFilePath, err) | |
} | |
configuration := &Configuration{} | |
err = yaml.Unmarshal(data, configuration) | |
if err != nil { | |
return nil, fmt.Errorf("failed to parse yaml file %s: %s", configFilePath, err) | |
} | |
return configuration, nil | |
} |
And finally a part of main function in our application, where we use parameter to pass a path to the configuration file, and load it to use configuration later:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"log" | |
) | |
var configFile = flag.String("config", "", "path to the configuration file") | |
func main() { | |
flag.Parse() | |
// load configuration | |
configuration, err := config.LoadConfiguration(*configFile) | |
if err != nil { | |
log.Fatalf("failed to read configuration file: %s", err) | |
} | |
// now can use `configuration` value | |
} |
That's it. Simple and fast!