configs

package
v0.0.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2025 License: MIT Imports: 6 Imported by: 0

README

Configs Package

A generic, flexible configuration loader for Go applications using Viper with support for defaults and environment-specific overrides.

Features

  • Generic Configuration Loading: Use any struct with the fluent API
  • Layered Configuration: Load from multiple sources with proper precedence
  • Environment-Specific Configs: Support for different environments (dev, prod, test)
  • Environment Variable Override: Automatic environment variable mapping
  • Fluent API: Clean, chainable interface for configuration loading
  • Optional Default Configs: Pre-built configs available in configs/defaults package

Quick Start

package main

import (
    "fmt"
    "log"
    
    "github.com/vnteam/go-utils/configs"
)

type MyConfig struct {
    Name string `mapstructure:"NAME"`
    Port int    `mapstructure:"PORT"`
    Host string `mapstructure:"HOST"`
}

func main() {
    cfg := &MyConfig{}
    
    err := configs.New(cfg).Load(configs.AppEnvironmentDev, "./configs")
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("App: %s, Port: %d, Host: %s\n", cfg.Name, cfg.Port, cfg.Host)
}

Configuration Loading Flow

The config loader follows a simple, predictable flow:

  1. Load config.example.yaml (base defaults) - if it exists
  2. Merge config.yaml (overrides) - if it exists
  3. Merge config.{env}.yaml (environment-specific) - if it exists
  4. Merge environment variables (highest priority)

Note: If both config.yaml and config.example.yaml exist, they are merged with config.yaml taking precedence over config.example.yaml.

Usage Examples

Basic Configuration
type AppConfig struct {
    Name string `mapstructure:"APP_NAME"`
    Port int    `mapstructure:"PORT"`
    Host string `mapstructure:"HOST"`
}

cfg := &AppConfig{}
err := configs.New(cfg).Load(configs.AppEnvironmentDev, "./configs")
With Custom Viper Instance
v := viper.New()
v.SetConfigName("my-config")
v.SetConfigType("yaml")

cfg := &MyConfig{}
err := configs.New(cfg).WithViper(v).Load(configs.AppEnvironmentDev, "./configs")
Environment-Specific Configuration
# config.example.yaml (base defaults)
app_name: "my-app"
port: 8080
host: "localhost"

# config.prod.yaml (production overrides)
app_name: "my-app-prod"
port: 80
host: "prod.example.com"

Using Default Configurations

The configs package includes pre-built database and messaging configurations:

import "github.com/vnteam/go-utils/configs"

type AppConfig struct {
    AppName string                    `mapstructure:"APP_NAME"`
    AppEnv  configs.AppEnvironment   `mapstructure:"APP_ENV"`
    Database configs.PostgresConfig  `mapstructure:"DATABASE"`
    Redis   configs.RedisConfig      `mapstructure:"REDIS"`
    Telegram configs.TelegramConfig  `mapstructure:"TELEGRAM"`
}

cfg := &AppConfig{}
err := configs.New(cfg).Load(configs.AppEnvironmentDev, "./configs")

Configuration File Structure

configs/
├── config.example.yaml    # Base defaults (required)
├── config.yaml           # General overrides (optional)
├── config.dev.yaml       # Development overrides (optional)
├── config.prod.yaml      # Production overrides (optional)
└── config.test.yaml      # Test overrides (optional)

Environment Variables

Environment variables automatically override config file values:

export APP_NAME="my-app"
export PORT=9000
export DATABASE_HOST="prod-db.example.com"

API Reference

ConfigLoader
type ConfigLoader[T any] struct {
    config *T
    viper  *viper.Viper
}
Methods
  • New[T any](cfg *T) *ConfigLoader[T] - Create a new config loader
  • WithViper(v *viper.Viper) *ConfigLoader[T] - Use a custom Viper instance
  • Load(appEnv AppEnvironment, configPath string) error - Load configuration
AppEnvironment
type AppEnvironment string

const (
    AppEnvironmentDev  AppEnvironment = "dev"
    AppEnvironmentProd AppEnvironment = "prod"
    AppEnvironmentTest AppEnvironment = "test"
)

Default Configurations

The configs package provides pre-built configuration structs:

Database Configurations
  • PostgresConfig - PostgreSQL database configuration
  • MySQLConfig - MySQL database configuration
  • RedisConfig - Redis configuration
  • MongoDBConfig - MongoDB configuration
Messaging Configurations
  • TelegramConfig - Telegram bot configuration
  • EmailConfig - Email/SMTP configuration
Example Usage
import "github.com/vnteam/go-utils/configs"

// Use individual configs
postgres := &configs.PostgresConfig{}
redis := &configs.RedisConfig{}

// Or use the complete AppConfig
appConfig := &configs.AppConfig{}

Best Practices

  1. Use config.example.yaml for defaults - This provides a clear template for all required configuration
  2. Environment-specific overrides - Use config.{env}.yaml for environment-specific settings
  3. Environment variables for secrets - Use env vars for sensitive data like passwords and API keys
  4. Keep configs simple - Avoid deeply nested structures when possible
  5. Use the defaults package sparingly - Only import what you need

Migration from Old Config System

If you're migrating from the old config system:

  1. Use generic loader - configs.New(cfg).Load(env, path)
  2. Update struct tags - Remove validate and default tags, keep only mapstructure
  3. Use config files for defaults - Use config.example.yaml instead of struct tags

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetServerPort

func GetServerPort(defaultServicePort string) string

GetServerPort returns the port for the main service. Priority is given to the port set from the environment variable. Then it checks the default value.

func ParseConfigDir

func ParseConfigDir(defaultDir string) string

Types

type AppConfig

type AppConfig struct {
	// App settings
	AppName     string         `mapstructure:"APP_NAME"`
	AppEnv      AppEnvironment `mapstructure:"APP_ENV"`
	AppLogPath  string         `mapstructure:"APP_LOG_PATH"`
	AppLogLevel string         `mapstructure:"APP_LOG_LEVEL"`

	// Databases
	Database PostgresConfig `mapstructure:"DATABASE"`
	MySQL    *MySQLConfig   `mapstructure:"MYSQL"`
	Redis    RedisConfig    `mapstructure:"REDIS"`
	MongoDB  *MongoDBConfig `mapstructure:"MONGODB"`

	// Messaging
	Telegram TelegramConfig `mapstructure:"TELEGRAM"`
	Email    EmailConfig    `mapstructure:"EMAIL"`

	// Server settings
	ServerPort    int    `mapstructure:"SERVER_PORT"`
	ServerHost    string `mapstructure:"SERVER_HOST"`
	ServerTimeout int    `mapstructure:"SERVER_TIMEOUT"`

	// JWT settings
	JWTSecretKey     string        `mapstructure:"JWT_SECRET_KEY"`
	JWTExpiration    time.Duration `mapstructure:"JWT_EXPIRATION"`
	JWTRefreshExpiry time.Duration `mapstructure:"JWT_REFRESH_EXPIRY"`
}

AppConfig represents the main application configuration.

type AppEnvironment

type AppEnvironment string

AppEnvironment represents the application environment.

const (
	AppEnvironmentProd        AppEnvironment = "prod"
	AppEnvironmentDev         AppEnvironment = "dev"
	AppEnvironmentTest        AppEnvironment = "test"
	AppEnvironmentIntegration AppEnvironment = "integration"
)

func GetEnv

func GetEnv(key, defaultValue string) AppEnvironment

GetEnv returns the value of an environment variable or the default value if not set. Typical the environment variable is "APP_ENV".

func (AppEnvironment) IsDevelopment

func (e AppEnvironment) IsDevelopment() bool

func (AppEnvironment) IsIntegration

func (e AppEnvironment) IsIntegration() bool

func (AppEnvironment) IsProduction

func (e AppEnvironment) IsProduction() bool

func (AppEnvironment) IsTest

func (e AppEnvironment) IsTest() bool

type ConfigLoader

type ConfigLoader[T any] struct {
	// contains filtered or unexported fields
}

ConfigLoader is a generic configuration loader that provides a fluent API for loading configuration files with defaults, validation, and merging.

func New

func New[T any](cfg *T) *ConfigLoader[T]

New creates a new ConfigLoader for the given config struct.

func (*ConfigLoader[T]) Load

func (cl *ConfigLoader[T]) Load(appEnv AppEnvironment, configPath string) error

Load loads the configuration from files and environment variables. Simplified flow: 1. Load config.example.yaml (base) 2. Merge config.yaml (overrides) 3. Merge config.{env}.yaml (environment-specific) 4. Merge environment variables 5. Unmarshal into config struct 6. Run validation callback if provided

func (*ConfigLoader[T]) WithValidation

func (cl *ConfigLoader[T]) WithValidation(validator func(*T) error) *ConfigLoader[T]

WithValidation sets a validation callback that will be called after the config is loaded. The callback should return an error if the configuration is invalid.

Example:

cfg := &MyConfig{}
err := New(cfg).WithValidation(func(cfg *MyConfig) error {
    if cfg.Port <= 0 {
        return fmt.Errorf("port must be positive")
    }
    if cfg.Database.Host == "" {
        return fmt.Errorf("database host is required")
    }
    return nil
}).Load(AppEnvironmentDev, "./configs")

func (*ConfigLoader[T]) WithViper

func (cl *ConfigLoader[T]) WithViper(v *viper.Viper) *ConfigLoader[T]

WithViper sets a custom viper instance for the loader.

type EmailConfig

type EmailConfig struct {
	SMTPHost string `mapstructure:"SMTP_HOST"`
	SMTPPort int    `mapstructure:"SMTP_PORT"`
	From     string `mapstructure:"FROM"`
	Password string `mapstructure:"PASSWORD"`
	UseTLS   bool   `mapstructure:"USE_TLS"`
	Enabled  bool   `mapstructure:"ENABLED"`
}

EmailConfig represents email/SMTP configuration.

type MongoDBConfig

type MongoDBConfig struct {
	Host        string        `mapstructure:"HOST"`
	Port        int           `mapstructure:"PORT"`
	Database    string        `mapstructure:"DATABASE"`
	AuthSource  string        `mapstructure:"AUTH_SOURCE"`
	ReplicaSet  string        `mapstructure:"REPLICA_SET"`
	MaxPoolSize uint64        `mapstructure:"MAX_POOL_SIZE"`
	MinPoolSize uint64        `mapstructure:"MIN_POOL_SIZE"`
	Timeout     time.Duration `mapstructure:"TIMEOUT"`
	Enabled     bool          `mapstructure:"ENABLED"`
}

MongoDBConfig represents MongoDB configuration.

func (*MongoDBConfig) GetURI

func (c *MongoDBConfig) GetURI() string

GetURI returns the MongoDB connection URI.

type MySQLConfig

type MySQLConfig struct {
	Host            string        `mapstructure:"HOST"`
	Port            int           `mapstructure:"PORT"`
	User            string        `mapstructure:"USER"`
	Password        string        `mapstructure:"PASSWORD"`
	Database        string        `mapstructure:"DATABASE"`
	Charset         string        `mapstructure:"CHARSET"`
	ParseTime       bool          `mapstructure:"PARSE_TIME"`
	Loc             string        `mapstructure:"LOC"`
	MaxOpenConns    int           `mapstructure:"MAX_OPEN_CONNS"`
	MaxIdleConns    int           `mapstructure:"MAX_IDLE_CONNS"`
	ConnMaxLifetime time.Duration `mapstructure:"CONN_MAX_LIFETIME"`
	ConnMaxIdleTime time.Duration `mapstructure:"CONN_MAX_IDLE_TIME"`
	Enabled         bool          `mapstructure:"ENABLED"`
}

MySQLConfig represents MySQL database configuration.

func (*MySQLConfig) GetDSN

func (c *MySQLConfig) GetDSN() string

GetDSN returns the MySQL DSN string.

type PostgresConfig

type PostgresConfig struct {
	Host            string        `mapstructure:"HOST"`
	Port            int           `mapstructure:"PORT"`
	User            string        `mapstructure:"USER"`
	Password        string        `mapstructure:"PASSWORD"`
	Database        string        `mapstructure:"DATABASE"`
	SSLMode         string        `mapstructure:"SSL_MODE"`
	Timezone        string        `mapstructure:"TIMEZONE"`
	MaxOpenConns    int           `mapstructure:"MAX_OPEN_CONNS"`
	MaxIdleConns    int           `mapstructure:"MAX_IDLE_CONNS"`
	ConnMaxLifetime time.Duration `mapstructure:"CONN_MAX_LIFETIME"`
	ConnMaxIdleTime time.Duration `mapstructure:"CONN_MAX_IDLE_TIME"`
	Enabled         bool          `mapstructure:"ENABLED"`
}

PostgresConfig represents PostgreSQL database configuration.

func (*PostgresConfig) GetDSN

func (c *PostgresConfig) GetDSN() string

GetDSN returns the PostgreSQL DSN string.

type RedisConfig

type RedisConfig struct {
	Host         string        `mapstructure:"HOST"`
	Port         int           `mapstructure:"PORT"`
	DB           int           `mapstructure:"DB"`
	Password     string        `mapstructure:"PASSWORD"`
	PoolSize     int           `mapstructure:"POOL_SIZE"`
	MaxRetries   int           `mapstructure:"MAX_RETRIES"`
	DialTimeout  time.Duration `mapstructure:"DIAL_TIMEOUT"`
	ReadTimeout  time.Duration `mapstructure:"READ_TIMEOUT"`
	WriteTimeout time.Duration `mapstructure:"WRITE_TIMEOUT"`
	Enabled      bool          `mapstructure:"ENABLED"`
}

RedisConfig represents Redis configuration.

func (*RedisConfig) GetAddr

func (c *RedisConfig) GetAddr() string

GetAddr returns the Redis address string.

type TelegramConfig

type TelegramConfig struct {
	BotToken        string `mapstructure:"BOT_TOKEN"`
	ChannelID       int64  `mapstructure:"CHANNEL_ID"`
	MessageThreadID int64  `mapstructure:"MESSAGE_THREAD_ID"`
	Enabled         bool   `mapstructure:"ENABLED"`
}

TelegramConfig represents Telegram bot configuration.

type TelegramConfigs

type TelegramConfigs []*TelegramConfig

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL