Documentation ¶
Overview ¶
Package conf provides a way to load configuration from JSON files and environment variables, along with a structure to hold the configuration settings for an application and the ability to set up command-line flags for configuration options.
Example ¶
package main import ( "fmt" "os" "github.com/patrickward/hop/conf" ) func main() { // STEP1: Define a custom configuration struct that embeds BaseConfig type AppConfig struct { conf.BaseConfig // Inherit base configuration Redis struct { Host string `json:"host" env:"REDIS_HOST" default:"localhost"` Port int `json:"port" env:"REDIS_PORT" default:"6379"` Timeout conf.Duration `json:"timeout" env:"REDIS_TIMEOUT" default:"5s"` } `json:"redis"` API struct { Endpoint string `json:"endpoint" env:"API_ENDPOINT" default:"http://api.local"` Timeout conf.Duration `json:"timeout" env:"API_TIMEOUT" default:"30s"` } `json:"api"` } // Create a temporary config file (for example purposes only) configJSON := `{ "environment": "production", "debug": false, "redis": { "host": "redis.prod.example.com", "timeout": "10s" }, "api": { "endpoint": "https://api.prod.example.com" } }` tmpfile, err := os.CreateTemp("", "config.*.json") if err != nil { fmt.Printf("Error creating temp file: %v\n", err) return } defer func(name string) { _ = os.Remove(name) }(tmpfile.Name()) if _, err := tmpfile.Write([]byte(configJSON)); err != nil { fmt.Printf("Error writing temp file: %v\n", err) return } _ = tmpfile.Close() // Set some environment variables (for example purposes only) _ = os.Setenv("REDIS_PORT", "6380") _ = os.Setenv("API_TIMEOUT", "45s") // STEP2: Create and load configuration cfg := &AppConfig{} if err := conf.Load(cfg, tmpfile.Name()); err != nil { fmt.Printf("Error loading config: %v\n", err) return } // Print the resulting configuration fmt.Printf("Environment: %s\n", cfg.App.Environment) fmt.Printf("Redis Host: %s\n", cfg.Redis.Host) fmt.Printf("Redis Port: %d\n", cfg.Redis.Port) fmt.Printf("Redis Timeout: %s\n", cfg.Redis.Timeout) fmt.Printf("API Endpoint: %s\n", cfg.API.Endpoint) fmt.Printf("API Timeout: %s\n", cfg.API.Timeout) }
Output: Environment: production Redis Host: redis.prod.example.com Redis Port: 6380 Redis Timeout: 10s API Endpoint: https://api.prod.example.com API Timeout: 45s
Index ¶
- func ApplyFlagOverrides(cfg *BaseConfig, fs *flag.FlagSet)
- func BasicFlags(fs *flag.FlagSet)
- func Load(cfg interface{}, files ...string) error
- func NewFlagSet(appName string, errorHandling flag.ErrorHandling) *flag.FlagSet
- type AppConfig
- type BaseConfig
- type CompanyConfig
- type DatabaseConfig
- type Duration
- type LogConfig
- type MaintenanceConfig
- type SMPTConfig
- type ServerConfig
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyFlagOverrides ¶
func ApplyFlagOverrides(cfg *BaseConfig, fs *flag.FlagSet)
ApplyFlagOverrides ensures that if a basic flag is set, it overrides the config
func BasicFlags ¶
BasicFlags sets up the common flags most apps will need
Example ¶
package main import ( "flag" "fmt" "io" "os" "github.com/patrickward/hop/conf" ) func main() { // STEP1: Define a custom configuration struct type AppConfig struct { conf.BaseConfig API struct { Endpoint string `json:"endpoint" env:"API_ENDPOINT" default:"http://api.local"` Timeout conf.Duration `json:"timeout" env:"API_TIMEOUT" default:"30s"` } `json:"api"` } // Create a temporary config file (for example purposes only) configJSON := `{ "api": { "endpoint": "https://api.example.com" } }` tmpfile, err := os.CreateTemp("", "config.*.json") if err != nil { fmt.Printf("Error creating temp file: %v\n", err) return } defer func(name string) { _ = os.Remove(name) }(tmpfile.Name()) if _, err := tmpfile.Write([]byte(configJSON)); err != nil { fmt.Printf("Error writing temp file: %v\n", err) return } _ = tmpfile.Close() // Save and restore os.Args (for example purposes only) oldArgs := os.Args defer func() { os.Args = oldArgs }() // Simulate command line arguments os.Args = []string{ "myapp", "--config", tmpfile.Name(), "--env", "production", "--debug", "--api-timeout", "1m", } // STEP2: Set up flags fs := flag.NewFlagSet("myapp", flag.ContinueOnError) fs.SetOutput(io.Discard) // Disable flag output for example // STEP3: Add basic flags conf.BasicFlags(fs) // STEP4: Add custom flags for this application apiTimeout := fs.Duration("api-timeout", 0, "API timeout duration") // STEP5: Parse flags _ = fs.Parse(os.Args[1:]) // STEP6: Create and load configuration cfg := &AppConfig{} if err := conf.Load(cfg, fs.Lookup("config").Value.String()); err != nil { fmt.Printf("Error loading config: %v\n", err) return } // STEP7: Apply flag overrides conf.ApplyFlagOverrides(&cfg.BaseConfig, fs) // Apply other flag values that should override config if apiTimeout != nil && *apiTimeout != 0 { cfg.API.Timeout = conf.Duration{Duration: *apiTimeout} } // Print the resulting configuration fmt.Printf("Environment: %s\n", cfg.App.Environment) fmt.Printf("Debug: %v\n", cfg.App.Debug) fmt.Printf("API Endpoint: %s\n", cfg.API.Endpoint) fmt.Printf("API Timeout: %s\n", cfg.API.Timeout) }
Output: Environment: production Debug: true API Endpoint: https://api.example.com API Timeout: 1m0s
func Load ¶
Load sets the defaults and loads configuration from JSON files and environment variables
func NewFlagSet ¶
func NewFlagSet(appName string, errorHandling flag.ErrorHandling) *flag.FlagSet
Types ¶
type BaseConfig ¶
type BaseConfig struct { //Environment string `json:"environment" env:"APP_ENVIRONMENT" default:"development"` //Debug bool `json:"debug" env:"APP_DEBUG" default:"false"` App AppConfig `json:"app"` Company CompanyConfig `json:"company"` Maintenance MaintenanceConfig `json:"maintenance"` Server ServerConfig `json:"server"` Database DatabaseConfig `json:"database"` SMTP SMPTConfig `json:"smtp"` Log LogConfig `json:"log"` }
BaseConfig provides core configuration options
func (*BaseConfig) IsDevelopment ¶
func (c *BaseConfig) IsDevelopment() bool
func (*BaseConfig) IsProduction ¶
func (c *BaseConfig) IsProduction() bool
type CompanyConfig ¶
type CompanyConfig struct { Address string `json:"address" env:"COMPANY_ADDRESS" default:""` Name string `json:"name" env:"COMPANY_NAME" default:""` LogoURL string `json:"logo_url" env:"COMPANY_LOGO_URL" default:""` SupportEmail string `json:"support_email" env:"COMPANY_SUPPORT_EMAIL" default:""` WebsiteName string `json:"website_name" env:"COMPANY_WEBSITE_NAME" default:""` WebsiteURL string `json:"website_url" env:"COMPANY_WEBSITE_URL" default:""` }
type DatabaseConfig ¶
type DatabaseConfig struct { Driver string `json:"driver" env:"DB_DRIVER" default:"sqlite"` URI string `json:"uri" env:"DB_URI" default:"data/db.sqlite"` Timeout Duration `json:"timeout" env:"DB_TIMEOUT" default:"10s"` MaxIdleConns int `json:"max_idle_conns" env:"DB_MAX_IDLE_CONNS" default:"10"` MaxIdleTime Duration `json:"max_idle_time" env:"DB_MAX_IDLE_TIME" default:"5m"` MaxConnLifetime Duration `json:"max_conn_lifetime" env:"DB_MAX_CONN_LIFETIME" default:"30m"` AutoMigrate bool `json:"auto_migrate" env:"DB_AUTO_MIGRATE" default:"false"` }
type Duration ¶
Duration is a wrapper around time.Duration that supports JSON marshaling/unmarshaling
Example ¶
ExampleDuration demonstrates how to use the Duration type
package main import ( "fmt" "os" "github.com/patrickward/hop/conf" ) func main() { type Config struct { Timeout conf.Duration `json:"timeout" env:"TIMEOUT" default:"30s"` } cfg := &Config{} // Load with just defaults if err := conf.Load(cfg); err != nil { fmt.Printf("Error loading config: %v\n", err) return } fmt.Printf("Default timeout: %s\n", cfg.Timeout) // Set environment variable _ = os.Setenv("TIMEOUT", "1m30s") // Load again with environment variable if err := conf.Load(cfg); err != nil { fmt.Printf("Error loading config: %v\n", err) return } fmt.Printf("Environment timeout: %s\n", cfg.Timeout) }
Output: Default timeout: 30s Environment timeout: 1m30s
func (Duration) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface
func (*Duration) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler interface
type MaintenanceConfig ¶
type SMPTConfig ¶
type SMPTConfig struct { Host string `json:"host" env:"SMTP_HOST" default:"localhost"` Port int `json:"port" env:"SMTP_PORT" default:"1025"` Username string `json:"username" env:"SMTP_USERNAME" default:""` Password string `json:"password" env:"SMTP_PASSWORD" default:""` From string `json:"from" env:"SMTP_FROM" default:""` AuthType string `json:"auth_type" env:"SMTP_AUTH_TYPE" default:"LOGIN"` TLSPolicy int `json:"tls_policy" env:"SMTP_TLS_POLICY" default:"1"` RetryCount int `json:"retry_count" env:"SMTP_RETRY_COUNT" default:"3"` RetryDelay Duration `json:"retry_delay" env:"SMTP_RETRY_DELAY" default:"5s"` }
type ServerConfig ¶
type ServerConfig struct { BaseURL string `json:"base_url" env:"SERVER_BASE_URL" default:"http://localhost:4444"` Host string `json:"host" env:"SERVER_HOST" default:"localhost"` Port int `json:"port" env:"SERVER_PORT" default:"4444"` IdleTimeout Duration `json:"idle_timeout" env:"SERVER_IDLE_TIMEOUT" default:"120s"` ReadTimeout Duration `json:"read_timeout" env:"SERVER_READ_TIMEOUT" default:"15s"` WriteTimeout Duration `json:"write_timeout" env:"SERVER_WRITE_TIMEOUT" default:"15s"` ShutdownTimeout Duration `json:"shutdown_timeout" env:"SERVER_SHUTDOWN_TIMEOUT" default:"10s"` }