configuration API

configuration

package

API reference for the configuration package.

I
interface

Provider

Provider is the interface that configuration sources must implement.

pkg/configuration/config.go:25-31
type Provider interface

Example

type MyProvider struct{}
func (p *MyProvider) Name() string { return "my" }
func (p *MyProvider) Load(ctx) (map[string]any, error) { return map[string]any{"key": "val"}, nil }

Methods

Name
Method

Returns

string
func Name(...)
Load
Method

Parameters

Returns

map[string]any
error
func Load(...)
S
struct

Configuration

Configuration holds merged configuration data from multiple providers.

pkg/configuration/config.go:42-45
type Configuration struct

Example

cfg := configuration.NewBuilder().
    AddEnv("APP_").
    AddJSONFile("config.json").
    Build()
val := cfg.Get("db:host")

Methods

Get
Method

Get returns the value for the given key. The key is case-insensitive. Nested keys can be accessed with colon syntax, e.g. "db:host".

Parameters

key string

Returns

any
bool
func (*Configuration) Get(key string) (any, bool)
{
	c.mu.RLock()
	defer c.mu.RUnlock()
	v, ok := c.data[strings.ToLower(key)]
	return v, ok
}
GetString
Method

GetString returns the string value for the given key.

Parameters

key string

Returns

string
bool
func (*Configuration) GetString(key string) (string, bool)
{
	v, ok := c.Get(key)
	if !ok {
		return "", false
	}
	s, ok := v.(string)
	return s, ok
}
GetInt
Method

GetInt returns the int value for the given key.

Parameters

key string

Returns

int
bool
func (*Configuration) GetInt(key string) (int, bool)
{
	v, ok := c.Get(key)
	if !ok {
		return 0, false
	}
	switch n := v.(type) {
	case int:
		return n, true
	case float64:
		return int(n), true
	case string:
		i, err := strconv.Atoi(n)
		return i, err == nil
	}
	return 0, false
}
GetBool
Method

GetBool returns the bool value for the given key.

Parameters

key string

Returns

bool
bool
func (*Configuration) GetBool(key string) (bool, bool)
{
	v, ok := c.Get(key)
	if !ok {
		return false, false
	}
	switch b := v.(type) {
	case bool:
		return b, true
	case string:
		return strings.ToLower(b) == "true" || b == "1", true
	}
	return false, false
}
GetSection
Method

GetSection returns a new Configuration containing only keys with the given prefix.

Parameters

prefix string

Returns

func (*Configuration) GetSection(prefix string) *Configuration
{
	prefix = strings.ToLower(prefix) + ":"
	c.mu.RLock()
	defer c.mu.RUnlock()

	section := New()
	for k, v := range c.data {
		if strings.HasPrefix(k, prefix) {
			section.data[strings.TrimPrefix(k, prefix)] = v
		}
	}
	return section
}
Bind
Method

Bind populates a struct from the configuration data. Fields are matched using the `conf` tag. If no tag is present, the field name is used as key.

Parameters

target any

Returns

error
func (*Configuration) Bind(target any) error
{
	val := reflect.ValueOf(target)
	if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct {
		return fmt.Errorf("configuration: target must be a pointer to a struct")
	}

	c.mu.RLock()
	defer c.mu.RUnlock()

	elem := val.Elem()
	confParser := tags.NewParser("conf", tags.WithPairDelimiter(","))
	fields := confParser.ParseStruct(target)

	for _, meta := range fields {
		fieldVal := elem.Field(meta.Index)
		if !fieldVal.CanSet() {
			continue
		}

		key := meta.RawTag
		if key == "" {
			key = strings.ToLower(meta.Name)
		}

		var rawVal any
		found := false

		if v, ok := c.data[strings.ToLower(key)]; ok {
			rawVal = v
			found = true
		}

		if !found {
			if envKey := meta.Get("env"); envKey != "" {
				if v, ok := c.data[strings.ToLower(envKey)]; ok {
					rawVal = v
					found = true
				}
			}
		}

		if !found {
			if def := meta.Get("default"); def != "" {
				rawVal = def
				found = true
			}
		}

		if !found {
			continue
		}

		if err := setField(fieldVal, fmt.Sprintf("%v", rawVal)); err != nil {
			return fmt.Errorf("configuration: field %s: %w", meta.Name, err)
		}
	}

	return nil
}
Example
type Config struct {
    Host string `conf:"db:host"`
    Port int    `conf:"db:port" default:"5432"`
}
var cfg Config
err := configuration.Bind(&cfg)

Fields

Name Type Description
mu sync.RWMutex
data map[string]any
F
function

New

New creates an empty Configuration.

Returns

pkg/configuration/config.go:202-206
func New() *Configuration

{
	return &Configuration{
		data: make(map[string]any),
	}
}
S
struct

Builder

Builder provides a fluent API for assembling a Configuration from multiple
sources with priority ordering (last added wins).

pkg/configuration/config.go:217-219
type Builder struct

Example

cfg := configuration.NewBuilder().
    AddEnv("APP_").
    AddJSONFile("config.json").
    Build()

Methods

Add
Method

Add registers a configuration provider. Providers added later take priority over earlier ones for overlapping keys.

Parameters

Returns

func (*Builder) Add(p Provider) *Builder
{
	b.providers = append(b.providers, p)
	return b
}
Build
Method

Build merges all registered providers into a single Configuration. Providers are queried in order; later providers override earlier ones.

Parameters

Returns

error
func (*Builder) Build(ctx context.Context) (*Configuration, error)
{
	cfg := New()
	for _, p := range b.providers {
		data, err := p.Load(ctx)
		if err != nil {
			return nil, fmt.Errorf("configuration: source %q failed: %w", p.Name(), err)
		}
		cfg.mu.Lock()
		for k, v := range data {
			cfg.data[strings.ToLower(k)] = v
		}
		cfg.mu.Unlock()
	}
	return cfg, nil
}

Fields

Name Type Description
providers []Provider
F
function

NewBuilder

NewBuilder creates a new Builder.

Returns

pkg/configuration/config.go:222-224
func NewBuilder() *Builder

{
	return &Builder{}
}
F
function

setField

Parameters

valStr
string

Returns

error
pkg/configuration/config.go:251-283
func setField(field reflect.Value, valStr string) error

{
	switch field.Kind() {
	case reflect.String:
		field.SetString(valStr)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		n, err := strconv.ParseInt(valStr, 10, 64)
		if err != nil {
			return err
		}
		field.SetInt(n)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		n, err := strconv.ParseUint(valStr, 10, 64)
		if err != nil {
			return err
		}
		field.SetUint(n)
	case reflect.Bool:
		b, err := strconv.ParseBool(valStr)
		if err != nil {
			return err
		}
		field.SetBool(b)
	case reflect.Float32, reflect.Float64:
		n, err := strconv.ParseFloat(valStr, 64)
		if err != nil {
			return err
		}
		field.SetFloat(n)
	default:
		return fmt.Errorf("unsupported type %s", field.Kind())
	}
	return nil
}