making Configuration boring in Go with Constructor
- tags
- #Go #Code #Open Source
- published
- reading time
- 2 minutes
While the 12 Factor App advocates for using environment variables in configuration, I felt the need for a more comprehensive solution. This realization prompted the creation of Constructor, a lightweight Go library/module. Its purpose is to streamline the configuration process by simplifying structs through tags, default values, and support for overrides from YAML files, environment variables, and flags.
In summary, Constructor is designed to elevate the configuration experience in Go, providing an efficient and versatile solution to eliminate repetitive tasks across various applications.
Principles for Configurations
For all or most applications and services, the following principles of configuration should hold true:
- Structured Management: Configurations should be stored and managed in a structured manner.
- Automatic Default Loading: Configuration should automatically load defaults without excessive code.
- Flexible Overrides: Configuration variables should be easily overridden by config files, environmental variables, and flags/switches, with a defined order or priority by making use of metadata/tags
graph LR default --> c[config file] --> e[enviriomental varaibles] --> f[flags / swithces]
Introducing Constructor: A Configuration Simplification Library
I created the Constructor library to address these principles. It simplifies the process of coding out configuration loading in Go.
Getting Started
To use Constructor, first, get the module:
go get gitlab.com/libsToGo/constructor
Creating and Setting Defaults
Create the configuration struct and set the default values using tags:
type myConfig struct {
Version int `default:"1"`
LogLevel string `default:"dev"`
}
func main() {
// Create the struct with default values
config := myConfig{}
constructor.SetDefaults(&config)
}
Adding Overrides
Now, you can decide how and what gets changed with flags, environmental variables, etc., by adding tags to the struct:
type myConfig struct {
Version int `default:"1" env:"VER"`
LogLevel string `default:"dev" env:"LOG_LEVEL" flag:"l" definition:"the log level"`
}
Override Sequence and Priority
Define the override sequence and priority:
func main() {
// Create the struct with defaults
config := myConfig{}
constructor.SetDefaults(&config)
// Override defaults from YAML if present
err := constructor.OverrideFromYAML(&config, "myYaml.yaml")
if err != nil {
log.Fatal(err)
}
// Override everything with environmental variables
constructor.OverrideFromEnv(&config)
// Override with flags
flags := constructor.OverrideFromFlags(&config)
flags.Parse(os.Args[1:])
flags.PrintDefaults()
}
With Constructor, managing configurations in Go becomes a straightforward process, allowing you to focus on building robust applications without the hassle of writing tedious code.
The readme of the repo gives a better overview of what can be done and how it is used