loader provides easy to use object loading capability.
Sometimes, we need to load the same object from multiple sources in order of priority.
For example, the configuration data of the application:
- Built-in default value
- Load from the configuration file
- Load from environment variables
- Parse from the command line parameter
- Other sources (centralized configuration management, etc.)
loader provides a surprisingly simple pattern.
-
Get package:
go get -u github.com/cnotch/loader
-
Import it in your code:
import "github.com/cnotch/loader"
For example, load configuration, which typically consists of the following steps:
- Define configuration structure
type Config struct {
Log LogConfig `json:"log,omitempty"`
Rtsp RtspConfig `json:"rtsp"`
}
type RtspConfig struct {
Port int `json:"port"`
}
type LogConfig struct {
Debug bool `json:"debug"`
}
- Load by priority
import (
"flag"
"github.com/cnotch/loader"
)
const (
envPrefix = "APP"
)
func LoadConfig(configPath string) *Config {
conf := new(Config)
// Define the initialization loader
initLoader := func(cfg interface{}) error {
flag.BoolVar(&conf.Log.Debug, "log-debug", false, "Enable debug level log")
flag.IntVar(&conf.Rtsp.Port, "rtsp-port", 554, "Set RTSP listen port")
return nil
}
// load the config in the following order:
// load from init then
// load from json then
// load from environment vars then
// load from command-line flag.
if err := loader.Load(conf,
loader.Func(initLoader),
&loader.JSONLoader{Path: configPath, CreatedIfNonExsit: true},
&loader.EnvLoader{Prefix: envPrefix},
&loader.FlagLoader{}); err != nil {
panic(err)
}
return conf
}
When used to load configurations, loader takes care of simplicity and compatibility, and take full advantage of the built-in flag package with little additional constraints.