Type-Safe Getters

Access configuration values with compile-time type safety, variadic defaults, and advanced functional options.

Confy provides type-safe getter methods for all common Go types. Every getter accepts optional default values using variadic arguments.

Basic Getters

All basic getters follow the pattern Get<Type>(key, ...defaults):

cfg := confy.New()
cfg.LoadFrom(source)

// String
host := cfg.GetString("database.host", "localhost")
name := cfg.GetString("app.name") // returns "" if missing

// Integers
port := cfg.GetInt("server.port", 8080)
workers := cfg.GetInt64("pool.workers", 4)

// Floats
rate := cfg.GetFloat64("rate_limit", 1.5)

// Boolean
debug := cfg.GetBool("debug", false)

// Duration (parses "30s", "5m", "1h")
timeout := cfg.GetDuration("timeout", 30*time.Second)

// Time
expiry := cfg.GetTime("token.expiry")

// Size in bytes (parses "10MB", "1GB")
maxSize := cfg.GetSizeInBytes("upload.max_size", 1024*1024)

Complete Type Reference

Scalar Types

MethodReturn TypeZero Value
GetStringstring""
GetIntint0
GetInt8int80
GetInt16int160
GetInt32int320
GetInt64int640
GetUintuint0
GetUint8uint80
GetUint16uint160
GetUint32uint320
GetUint64uint640
GetFloat32float320.0
GetFloat64float640.0
GetBoolboolfalse
GetDurationtime.Duration0
GetTimetime.Timezero time
GetSizeInBytesuint640

Collection Types

MethodReturn Type
GetStringSlice[]string
GetIntSlice[]int
GetInt64Slice[]int64
GetFloat64Slice[]float64
GetBoolSlice[]bool
GetStringMapmap[string]string
GetStringMapStringSlicemap[string][]string

Collection Examples

// Slices
hosts := cfg.GetStringSlice("cluster.hosts", []string{"localhost"})
ports := cfg.GetIntSlice("service.ports")

// Maps
headers := cfg.GetStringMap("http.headers", map[string]string{
    "X-Request-ID": "auto",
})

tags := cfg.GetStringMapStringSlice("service.tags")

Untyped Getter

The generic Get method returns any for dynamic access:

value := cfg.Get("some.key")

switch v := value.(type) {
case string:
    fmt.Println("string:", v)
case int:
    fmt.Println("int:", v)
case map[string]any:
    fmt.Println("map:", v)
}

Advanced Getters with Options

For more control, use the WithOptions variants that return both a value and an error:

port, err := cfg.GetIntWithOptions("server.port",
    confy.WithDefault(8080),
    confy.WithRequired(),
    confy.WithValidator(func(v any) error {
        if p, ok := v.(int); ok && (p < 1 || p > 65535) {
            return fmt.Errorf("port must be 1-65535, got %d", p)
        }
        return nil
    }),
)
if err != nil {
    log.Fatal(err)
}

Available Get Options

OptionDescription
WithDefault(value)Set a default value
WithRequired()Error if key is missing
WithValidator(fn)Validate the retrieved value
WithTransform(fn)Transform the value after retrieval
WithOnMissing(fn)Callback when key is missing
AllowEmpty()Allow empty string/zero values
WithCacheKey(key)Custom cache key for the result

Validation on Get

level, err := cfg.GetStringWithOptions("log.level",
    confy.WithDefault("info"),
    confy.WithValidator(func(v any) error {
        valid := map[string]bool{"debug": true, "info": true, "warn": true, "error": true}
        if s, ok := v.(string); ok && !valid[s] {
            return fmt.Errorf("invalid log level: %s", s)
        }
        return nil
    }),
)

Transform on Get

url, err := cfg.GetStringWithOptions("api.url",
    confy.WithTransform(func(v any) any {
        if s, ok := v.(string); ok {
            return strings.TrimRight(s, "/")
        }
        return v
    }),
)

Missing Key Callback

value, err := cfg.GetWithOptions("feature.flag",
    confy.WithOnMissing(func(key string) any {
        log.Printf("WARN: key %q not found, using fallback", key)
        return false
    }),
)

Key Paths

Configuration keys use dot notation for nested access:

# config.yaml
database:
  primary:
    host: localhost
    port: 5432
  pool:
    max_connections: 20
host := cfg.GetString("database.primary.host")      // "localhost"
port := cfg.GetInt("database.primary.port")          // 5432
maxConns := cfg.GetInt("database.pool.max_connections") // 20

Introspection

Check key existence and query metadata:

// Check if a key exists
if cfg.HasKey("database.host") {
    // key is present in the configuration
}

// Same as HasKey
if cfg.IsSet("feature.enabled") {
    // ...
}

// Get all keys
keys := cfg.GetKeys()

// Get a section as a map
dbConfig := cfg.GetSection("database")

// Get total number of keys
count := cfg.Size()

Type Conversion

Confy automatically converts between compatible types. For example:

  • String "42" → int 42
  • String "true" → bool true
  • String "30s"time.Duration of 30 seconds
  • String "10MB"uint64 of 10485760 bytes
  • Int 8080 → string "8080"
  • Float 3.14 → int 3

If type conversion fails, the getter returns the zero value for the requested type (or the default if provided). Use the WithOptions variants to detect conversion errors.

How is this guide?

On this page