Documentation
¶
Overview ¶
Example ¶
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/inovacc/config"
)
type ExampleServiceConfig struct {
Port int `yaml:"port"`
Host string `yaml:"host"`
}
func main() {
dir, _ := os.MkdirTemp("", "example-*")
defer func() { _ = os.RemoveAll(dir) }()
cfgPath := filepath.Join(dir, "config.yaml")
_ = os.WriteFile(cfgPath, []byte(`
appID: example-app-id-12345
appSecret: example-secret-12345678
logger:
logLevel: INFO
service:
port: 8080
host: localhost
`), 0644)
svc := &ExampleServiceConfig{}
if err := config.InitServiceConfig(svc, cfgPath); err != nil {
fmt.Println("error:", err)
return
}
cfg, err := config.GetServiceConfig[*ExampleServiceConfig]()
if err != nil {
fmt.Println("error:", err)
return
}
base := config.GetBaseConfig()
fmt.Printf("AppID: %s\n", base.AppID)
fmt.Printf("Host: %s, Port: %d\n", cfg.Host, cfg.Port)
}
Output: AppID: example-app-id-12345 Host: localhost, Port: 8080
Index ¶
- func AddMigration(from, to int, fn MigrationFunc)
- func AddValidator(fn ValidatorFunc)
- func DecryptValue(value string) (string, error)
- func DefaultConfig[T any](configPath string) error
- func EncryptValue(plaintext string) (string, error)
- func GetConfigVersion() int
- func GetServiceConfig[T any]() (T, error)
- func InitServiceConfig(v any, configPath string) error
- func IsEncryptedValue(s string) bool
- func LogConfig()
- func SetEncryptionKey(key []byte)
- func SetEnvPrefix(prefix string)
- func SetTargetVersion(version int)
- func WatchConfig(onChange ...func())
- type Config
- type Logger
- type MigrationFunc
- type ValidatorFunc
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddMigration ¶
func AddMigration(from, to int, fn MigrationFunc)
AddMigration registers a migration function that transforms config data from version `from` to version `to`. Migrations are run in order during InitServiceConfig when the config file's version is older than the target version.
Example:
config.AddMigration(1, 2, func(data map[string]any) error {
// Rename "logLevel" to "log_level" in logger section
if logger, ok := data["logger"].(map[string]any); ok {
if level, exists := logger["logLevel"]; exists {
logger["log_level"] = level
delete(logger, "logLevel")
}
}
data["version"] = 2
return nil
})
func AddValidator ¶
func AddValidator(fn ValidatorFunc)
AddValidator registers a custom validation function that will be called during InitServiceConfig after the built-in validation completes.
Validators receive a read-only copy of the Config and should return an error if validation fails. Multiple validators can be registered and they run in order.
Must be called before InitServiceConfig.
Example:
config.AddValidator(func(cfg config.Config) error {
svc, ok := cfg.Service.(*MyServiceConfig)
if !ok {
return fmt.Errorf("unexpected service config type")
}
if svc.Port < 1024 || svc.Port > 65535 {
return fmt.Errorf("port must be between 1024 and 65535, got %d", svc.Port)
}
return nil
})
Example ¶
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/inovacc/config"
)
type ExampleServiceConfig struct {
Port int `yaml:"port"`
Host string `yaml:"host"`
}
func main() {
dir, _ := os.MkdirTemp("", "example-validator-*")
defer func() { _ = os.RemoveAll(dir) }()
cfgPath := filepath.Join(dir, "config.yaml")
_ = os.WriteFile(cfgPath, []byte(`
appID: example-app-id-12345
appSecret: example-secret-12345678
logger:
logLevel: INFO
service:
port: 80
host: localhost
`), 0644)
config.AddValidator(func(cfg config.Config) error {
svc, ok := cfg.Service.(*ExampleServiceConfig)
if !ok {
return fmt.Errorf("unexpected service type")
}
if svc.Port < 1024 {
return fmt.Errorf("port must be >= 1024, got %d", svc.Port)
}
return nil
})
err := config.InitServiceConfig(&ExampleServiceConfig{}, cfgPath)
fmt.Println(err)
}
Output: custom validation: port must be >= 1024, got 80
func DecryptValue ¶
DecryptValue decrypts a value in the format ENC[base64data] and returns the plaintext string. If the value is not encrypted (no ENC[...] wrapper), it is returned unchanged.
Example:
plain, err := config.DecryptValue("ENC[base64...]")
func DefaultConfig ¶
DefaultConfig generates a base configuration file with random credentials and zeroed service configuration for a given type.
It should be used to bootstrap a config.yaml with sensible defaults.
Example:
err := config.DefaultConfig[*MyServiceConfig]("config.yaml")
if err != nil {
log.Fatal(err)
}
func EncryptValue ¶
EncryptValue encrypts a plaintext string and returns it in the format ENC[base64data]. The encryption key must be set first via SetEncryptionKey.
Use this to prepare values before storing them in a config file.
Example:
encrypted, err := config.EncryptValue("my-secret-password")
// encrypted = "ENC[base64...]"
func GetConfigVersion ¶
func GetConfigVersion() int
GetConfigVersion returns the current version from the loaded configuration.
func GetServiceConfig ¶
GetServiceConfig returns the previously registered service-specific configuration with type safety using generics.
If the type does not match what was stored, an error is returned.
Example:
cfg, err := config.GetServiceConfig[*MyServiceConfig]()
if err != nil {
log.Fatal(err)
}
func InitServiceConfig ¶
InitServiceConfig loads a configuration file and binds a service-specific struct to the `Service` field in the global config.
It must be called before accessing the service configuration via GetServiceConfig.
If the configuration file does not exist, a default one will be created. Default values from the provided service config struct will be used if corresponding values are not found in the configuration file.
After loading, if a profile-specific config file exists (e.g., "config.prod.yaml" when Environment is "prod"), its values are merged on top of the base config.
Example:
type MyServiceConfig struct {
Port int
Mode string
}
svc := &MyServiceConfig{
Port: 8080, // Default value
Mode: "dev", // Default value
}
err := config.InitServiceConfig(svc, "config.yaml")
if err != nil {
log.Fatal(err)
}
func IsEncryptedValue ¶
IsEncryptedValue reports whether s is in the ENC[...] format.
func LogConfig ¶
func LogConfig()
LogConfig logs the configuration at debug level, masking sensitive values.
This is a convenience method for safely logging the configuration.
Example:
config.LogConfig()
func SetEncryptionKey ¶
func SetEncryptionKey(key []byte)
SetEncryptionKey sets the key used for encrypting and decrypting configuration values. The key can be any length; it is hashed with SHA-256 to produce a 32-byte AES-256 key.
Must be called before InitServiceConfig if the config file contains encrypted values.
Example:
config.SetEncryptionKey([]byte(os.Getenv("CONFIG_KEY")))
func SetEnvPrefix ¶
func SetEnvPrefix(prefix string)
SetEnvPrefix sets a prefix for environment variables.
Environment variables that match the pattern {prefix}_* will override the corresponding configuration values. The matching is case-insensitive.
For example, if the prefix is "APP", then the environment variable "APP_LOGGER_LOGLEVEL" will override the value of "logger.logLevel" in the configuration file.
Must be called before InitServiceConfig.
Example:
config.SetEnvPrefix("APP")
func SetTargetVersion ¶
func SetTargetVersion(version int)
SetTargetVersion sets the expected config version. During InitServiceConfig, if the config file's version is lower than the target, registered migrations are applied in order. If no target is set, migrations are skipped.
Example:
config.SetTargetVersion(3)
func WatchConfig ¶
func WatchConfig(onChange ...func())
WatchConfig starts watching the configuration file for changes. When the file is modified, it is automatically re-read and the global configuration is updated. The optional onChange callback is invoked after each successful reload.
WatchConfig must be called after InitServiceConfig. It launches a background goroutine and returns immediately.
Example:
config.WatchConfig(func() {
log.Println("config reloaded")
})
Types ¶
type Config ¶
type Config struct {
Version int `yaml:"version" json:"version" mapstructure:"version"`
Environment string `yaml:"environment" json:"environment" mapstructure:"environment"`
AppVersion string `yaml:"-" json:"-" mapstructure:"-"`
ConfigFile string `yaml:"-" json:"-" mapstructure:"-"`
AppID string `yaml:"appID" json:"appID" mapstructure:"appID"`
AppSecret string `yaml:"appSecret" json:"appSecret" mapstructure:"appSecret" sensitive:"true"`
Logger Logger `yaml:"logger" json:"logger" mapstructure:"logger"`
Service any `yaml:"service" json:"service" mapstructure:"service"`
// contains filtered or unexported fields
}
Config represents the global application configuration.
Fields:
- Environment: The current environment (e.g., "dev", "prod").
- AppVersion: The application version.
- AppID: Unique application identifier.
- AppSecret: Secret key for the application (sensitive).
- Logger: Structured logging configuration.
- Service: Service-specific configuration.
func GetBaseConfig ¶
func GetBaseConfig() Config
GetBaseConfig returns a copy of the global configuration base object.
This allows safe read access to common fields like AppID, Logger, and AppSecret without exposing the global state to mutation.
Example:
cfg := config.GetBaseConfig()
fmt.Println("AppID:", cfg.AppID)
func GetSecureCopy ¶
func GetSecureCopy() Config
GetSecureCopy returns a copy of the configuration with sensitive values masked.
It masks the base AppSecret field and any fields tagged with `sensitive:"true"` in the service configuration struct.
This is useful for logging or displaying the configuration without exposing sensitive information like secrets or passwords.
Example:
secureCfg := config.GetSecureCopy()
fmt.Printf("%+v\n", secureCfg)
Example ¶
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/inovacc/config"
)
type ExampleSecureConfig struct {
Username string `yaml:"username"`
Password string `yaml:"password" sensitive:"true"`
}
func main() {
dir, _ := os.MkdirTemp("", "example-secure-*")
defer func() { _ = os.RemoveAll(dir) }()
cfgPath := filepath.Join(dir, "config.yaml")
_ = os.WriteFile(cfgPath, []byte(`
appID: example-app-id-12345
appSecret: example-secret-12345678
logger:
logLevel: INFO
service:
username: admin
password: s3cret!
`), 0644)
svc := &ExampleSecureConfig{}
if err := config.InitServiceConfig(svc, cfgPath); err != nil {
fmt.Println("error:", err)
return
}
secure := config.GetSecureCopy()
fmt.Printf("AppSecret: %s\n", secure.AppSecret)
svcCopy, ok := secure.Service.(*ExampleSecureConfig)
if ok {
fmt.Printf("Username: %s\n", svcCopy.Username)
fmt.Printf("Password: %s\n", svcCopy.Password)
}
}
Output: AppSecret: ******** Username: admin Password: ********
type Logger ¶
type Logger struct {
LogLevel string `yaml:"logLevel" json:"logLevel" mapstructure:"logLevel"`
}
Logger defines the configuration for structured logging.
type MigrationFunc ¶
MigrationFunc transforms the configuration from one version to the next. It receives a mutable map of the raw config data and should modify it in place (e.g., rename keys, change structure).
type ValidatorFunc ¶
ValidatorFunc is a function that validates the configuration. It receives a read-only copy of the Config and should return an error if validation fails.