Description: A Go library for parsing environment variables (and any other source) and setting corresponding flags. It is heavily inspired by Go's std flag
package in its design.
Why another package for parsing the environment? Currently, most popular environment parsing libraries depend on struct tags to map the environment to a structure and provide options like flag requirement or default values when absent.
With conf
and the use of Go Generics, we can now have a type-safe API that doesn't depend on struct tags and can take advantage of strong typing.
Let's contrast davidmdm/conf
with a popular environment parsing library github.com/kelseyhightower/envconfig
:
The envconfig approach is convenient but very sensitive to typos, and the defaults need to be encoded in their string format, which can be error-prone.
package main
import (
"time"
"github.com/kelseyhightower/envconfig"
)
type Config struct {
DatabaseURL string `envconfig:"DATABASE_URL" required:"true"`
Timeout time.Duration `envconfig:"TIMEMOUT" default:"5m"`
}
func main() {
var cfg Config
envconfig.Process("", &cfg)
}
On the other hand, davidmdm/conf
does not suffer from these problems. It also has the added benefit of being programmatic instead of static. If we need, environment variable names and options could be determined at runtime instead of statically typed into a struct definition.
package main
import (
"time"
"github.com/davidmdm/conf"
)
type Config struct {
DatabaseURL string
Timeout time.Duration
}
func main() {
var cfg Config
conf.Var(conf.Environ, &cfg.DatabaseURL, "DATABASE_URL", conf.Required[string](true))
conf.Var(conf.Environ, &cfg.Timeout, "TIMEOUT", conf.Default[time.Duration](5 * time.Minute))
conf.Environ.MustParse()
}
This Go package provides a flexible and extensible configuration parser that allows you to easily manage configuration settings in your Go applications. The parser supports environment variables, command line arguments, and file system-based configuration, making it adaptable to various deployment scenarios.
go get -u github.com/davidmdm/conf
Environment Variables: Retrieve configuration values from environment variables with the ability to set default values and mark certain configurations as required.
Command Line Arguments: Easily map command line flags to configuration variables, supporting case-insensitivity and automatic conversion of underscores to dashes.
File System Configuration: Load configuration settings from files in the file system, providing a convenient way to manage configuration files.
Multiple Sources: Combine any of the above sources or your own custom functions to lookup strings.
To get started, create a configuration parser using the MakeParser function:
import "github.com/davidmdm/conf"
// Create a configuration parser with optional lookup functions. By default if no lookup funcs are provided
// the parser will use os.Lookupenv
parser := conf.MakeParser()
You can provide one or more lookup functions to the MakeParser function, which will be used to retrieve configuration values.
Define your configuration variables using the Var function:
var (
yourStringVar string
yourIntVar int
)
conf.Var(parser, &yourStringVar, "YOUR_STRING_VAR", conf.Required[string](true))
conf.Var(parser, &yourIntVar, "YOUR_INT_VAR", conf.Default[int](42))
// In this example, YOUR_STRING_VAR is a required string variable, and YOUR_INT_VAR is an optional integer variable with a default value of 42.
Parse the configuration using the Parse or MustParse methods:
if err := parser.Parse(); err != nil {
// Handle configuration parsing errors
}
// Alternatively, use MustParse to panic on errors
parser.MustParse()
The package provides a default parser for environment variables conf.Environ
.
You can create one yourself:
environ := conf.MakeParser(os.Lookupenv)
Create a lookup function for command line arguments:
var (
path string
max int
)
args := conf.MakeParser(conf.CommandLineArgs())
conf.Var(args, "path", &path)
conf.Var(args, "max", &max)
args.MustParse()
Create a lookup function for file system-based configuration:
var (
secret string
)
fs := conf.MakeParser(conf.FileSystem(conf.FileSystemOptions{Base: "/path/to/config/files"}))
conf.Var(fs, "secret.txt", &secret)
fs.MustParse()
When creating a parser any number of lookup functions can be provided. For example you could read key/value pairs from maps, from a redis instance or any other key/value store.
Let's implement a Redis integration that isn't provided by conf:
var redisURL string
conf.Var(conf.Environ, "REDIS_URL", &redisURL, config.Required[string](true))
config.Environ.MustParse()
// Skipping error handling for example's sake
opt, _ := redis.ParseURL(redisURL)
client := redis.NewClient(opt)
rdb := conf.MakeParser(func(key string) (string, bool) {
value, err := rdb.Get(ctx, key)
if err != nil {
if err == redis.Nil {
return "", false
}
panic(err) // panics in lookup functions are recovered during parsing and presented as normal errors from Parse().
}
return value, true
})
conf.Var(rdb, ...)
rdb.MustParse()
You can pass more than one lookup function when creating a parser. It will look search each source in turn and attempt to use the first value it finds.
// First Lookup command line args, then fallback to os.Lookupenv
sources := conf.MakeParser(conf.CommandLineArgs(), os.Lookupenv)
var max int
// Note that commandline args automatically lower-cases and converts underscores to dashes before performing a lookup. This allows it to play nicely os.Lookupenv and allow you to override environment variables via command line args.
conf.Var(sources, &max, "MAX") // Can be configured via --max flag or MAX environment variable
sources.MustParse()
This project is licensed under the MIT License - see the LICENSE file for details