config

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 29, 2026 License: MIT Imports: 8 Imported by: 0

README

config

The config package provides configuration loading built on top of Viper. It is designed for shared service configuration where applications need a consistent way to load files, expand environment variables, validate data, and react to runtime changes.

Import

import "github.com/raykavin/gobox/config"

What it provides

  • support for file formats handled by Viper such as yaml, json, and toml
  • environment variable expansion inside configuration files
  • optional validation after loading
  • current config access through a thread-safe loader
  • change subscriptions and callbacks
  • debounced reload handling for watched config files

Main types

  • LoaderOptions[T]: configures the loader behavior
  • Loader[T]: loads, stores, watches, and reloads configuration
  • ConfigChangeEvent[T]: describes successful reloads or reload failures

Example

package main

import (
	"errors"
	"log"
	"time"

	"github.com/raykavin/gobox/config"
)

type AppConfig struct {
	AppName string `mapstructure:"app_name"`
	Port    int    `mapstructure:"port"`
	DBURL   string `mapstructure:"db_url"`
}

func main() {
	loader := config.NewViper[AppConfig](&config.LoaderOptions[AppConfig]{
		ConfigName:     "config",
		ConfigType:     "yaml",
		ConfigPaths:    []string{".", "./config"},
		WatchConfig:    true,
		ReloadDebounce: 2 * time.Second,
		OnConfigChange: func(cfg *AppConfig) {
			log.Printf("configuration reloaded for %s", cfg.AppName)
		},
		OnConfigChangeError: func(err error) {
			log.Printf("failed to reload configuration: %v", err)
		},
	})

	cfg, err := loader.LoadWithValidation(func(cfg *AppConfig) error {
		if cfg.Port == 0 {
			return errors.New("port is required")
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("starting %s on port %d", cfg.AppName, cfg.Port)
}

Example config file

app_name: my-service
port: 8080
db_url: ${DATABASE_URL}

Notes

  • Load() reads and stores the current config instance
  • LoadWithValidation() applies a validation function after loading
  • GetCurrent() returns the latest loaded config safely
  • Reload() refreshes the config from disk
  • Subscribe() and Unsubscribe() let consumers react to config changes
  • Stop() stops watchers and closes subscriber channels

Documentation

Overview

Package config provides configuration loading built on top of Viper.

It supports yaml, json, toml, and any other format Viper understands. Environment variables are expanded automatically inside configuration files, and an optional validator can reject invalid configurations at load time.

Basic loading

loader := config.NewViper[AppConfig](&config.LoaderOptions[AppConfig]{
    ConfigName:  "config",
    ConfigType:  "yaml",
    ConfigPaths: []string{".", "./config"},
})

cfg, err := loader.Load()

Loading with validation

cfg, err := loader.LoadWithValidation(func(c *AppConfig) error {
    if c.Port == 0 {
        return errors.New("port is required")
    }
    return nil
})

Watching for changes

Set WatchConfig: true to start a file watcher. Use Subscribe to receive typed change events, or OnConfigChange for a simpler callback.

ch := loader.Subscribe()
defer loader.Unsubscribe(ch)

for event := range ch {
    if event.Error != nil {
        log.Printf("reload failed: %v", event.Error)
        continue
    }
    log.Printf("config reloaded: port %d", event.NewConfig.Port)
}

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrConfigFileReadFailed   = errors.New("error reading configuration file")
	ErrConfigUnmarshalFailed  = errors.New("error parsing configuration")
	ErrConfigValidationFailed = errors.New("invalid configuration")
	ErrConfigReloadFailed     = errors.New("failed reloading the configuration")
	ErrValidationReloadFailed = errors.Join(ErrConfigReloadFailed, ErrConfigValidationFailed)
)

Functions

This section is empty.

Types

type ConfigChangeEvent

type ConfigChangeEvent[T any] struct {
	OldConfig *T        // Previous configuration
	NewConfig *T        // New configuration
	Error     error     // Error if reload failed
	Timestamp time.Time // Time of the event
}

ConfigChangeEvent represents a configuration change event

type ConfigWatcher

type ConfigWatcher[T any] interface {
	Subscribe() <-chan ConfigChangeEvent[T]
	Unsubscribe(<-chan ConfigChangeEvent[T])
}

ConfigWatcher defines subscription behavior for config changes

type Loader

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

Loader handles configuration loading and watching

func NewViper

func NewViper[T any](options *LoaderOptions[T]) *Loader[T]

NewViper creates a new configuration loader

func (*Loader[T]) GetCurrent

func (cl *Loader[T]) GetCurrent() *T

GetCurrent returns the current configuration safely

func (*Loader[T]) GetViper

func (cl *Loader[T]) GetViper() *viper.Viper

GetViper returns the underlying Viper instance

func (*Loader[T]) Load

func (cl *Loader[T]) Load() (*T, error)

Load loads configuration from file and expands environment variables

func (*Loader[T]) LoadWithValidation

func (cl *Loader[T]) LoadWithValidation(validator func(*T) error) (*T, error)

LoadWithValidation loads configuration and applies validation

func (*Loader[T]) Reload

func (cl *Loader[T]) Reload() error

Reload reloads configuration from file

func (*Loader[T]) Stop

func (cl *Loader[T]) Stop()

Stop stops the loader and releases resources

func (*Loader[T]) Subscribe

func (cl *Loader[T]) Subscribe() <-chan ConfigChangeEvent[T]

Subscribe registers a new subscriber for config changes

func (*Loader[T]) Unsubscribe

func (cl *Loader[T]) Unsubscribe(ch <-chan ConfigChangeEvent[T])

Unsubscribe removes a subscriber

type LoaderOptions

type LoaderOptions[T any] struct {
	ConfigName          string        // Configuration file name without extension
	ConfigType          string        // Configuration file type (yaml, json, toml, etc.)
	ConfigPaths         []string      // Paths where the configuration file is searched
	WatchConfig         bool          // Enables file watching for reload
	ReloadDebounce      time.Duration // Debounce duration for reload events
	OnConfigChange      func(*T)      // Callback executed on successful reload
	OnConfigChangeError func(error)   // Callback executed on reload error
}

LoaderOptions defines configuration loader options

func DefaultLoaderOptions

func DefaultLoaderOptions[T any]() *LoaderOptions[T]

DefaultLoaderOptions returns default configuration loader options

Jump to

Keyboard shortcuts

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