Home

Awesome

<div align="center">

 

<h1>konfetty 🎉</h1> <p><i>Zero-dependency, type-safe and powerful post-processing for your existing config solution in Go.</i></p>

 

go.dev reference codecov Go Report Card Maintainability

</div>

 

About <a id="about"></a>

Konfetty is a Go library that simplifies the management of hierarchical default values in complex struct hierarchies, primarily designed for, but not limited to, configuration management. It addresses the challenge of applying defaults to nested structs, interfaces, and embedded types while maintaining type safety.

Key features:

Konfetty aims to reduce the boilerplate typically associated with setting default values in Go struct hierarchies, allowing developers to focus on their core application logic rather than complex default value management.

Installation <a id="installation"></a>

go get -u github.com/nikoksr/konfetty

Quick Start <a id="quick-start"></a>

package main

import "github.com/nikoksr/konfetty"

type BaseDevice struct {
    Enabled bool
}

type LightDevice struct {
    BaseDevice
    Brightness int
}

type ThermostatDevice struct {
    BaseDevice
    Temperature float64
}

type RoomConfig struct {
    Devices []any
}

func main() {
	// Stubbing a configuration, usually pre-populated by your config provider, e.g., Viper or Koanf.
    cfg := &RoomConfig{
        Devices: []any{
            // A light device that's enabled by default
            &LightDevice{BaseDevice: BaseDevice{Enabled: true}},

            // A light device with a custom brightness
            &LightDevice{Brightness: 75},

            // An empty thermostat device
            &ThermostatDevice{},
        },
    }

    cfg, err := konfetty.FromStruct(cfg).
        WithDefaults(
        	// Devices are disabled by default
            BaseDevice{Enabled: false},

            // Light devices have a default brightness of 50
            LightDevice{Brightness: 50},

            // Thermostat devices have a default temperature of 20.0 and are enabled by default
            ThermostatDevice{
                // Override the base device default for thermostats
                BaseDevice: BaseDevice{Enabled: true},
			    Temperature: 20.0,
            },
        ).
        WithTransformer(func(cfg *RoomConfig) {
        	// Optional custom transformation logic for more complex processing
        }).
        WithValidator(func(cfg *RoomConfig) error {
            // Optional custom validation logic
            return nil
        }).
        Build()

    // Handle error ...

    // The processed config would look like this:
    //
    // {
    //   "Devices": [
    //     {
    //       // LightDevice
    //       "Enabled": true,     // Kept original value
    //       "Brightness": 50     // Used LightDevice default
    //     },
    //     {
    //       // LightDevice
    //       "Enabled": false,    // Used BaseDevice default
    //       "Brightness": 75     // Kept original value
    //     },
    //     {
    //       // ThermostatDevice
    //       "Enabled": true,     // Used ThermostatDevice default, overriding BaseDevice default
    //       "Temperature": 20.0  // Used ThermostatDevice default
    //     }
    //   ]
    // }

    // Continue using your config struct as usual ...
}

In this example, Konfetty automatically applies the BaseDevice defaults to all devices, then overlays the specific defaults for LightDevice and ThermostatDevice. This happens recursively through the entire RoomConfig structure all while maintaining compile-time type safety.

How Konfetty Works <a id="how-it-works"></a>

Konfetty's approach to default values sets it apart:

The processing pipeline: Recursively apply defaults > apply (optional) transformations > run (optional) validations

Integration <a id="integration"></a>

Konfetty doesn't replace your current config loading mechanism — it enhances it. Use it as a powerful post-processing step after loading your config with Viper, Koanf, or any other solution.

With Viper <a id="integration-viper"></a>

viper.ReadInConfig()
viper.Unmarshal(&config)

config, err := konfetty.FromStruct(&config).
    WithDefaults(defaultConfig).
    WithTransformer(transformer).
    WithValidator(validator).
    Build()

With Koanf <a id="integration-koanf"></a>

k := koanf.New(".")
k.Load(file.Provider("config.yaml"), yaml.Parser())
k.Unmarshal("", &config)

config, err := konfetty.FromStruct(&config).
    WithDefaults(defaultConfig).
    WithTransformer(transformer).
    WithValidator(validator).
    Build()

Usage Examples <a id="examples"></a>

Contributing <a id="contributing"></a>

Contributions are welcome! Please see our Contributing Guide for more details.

Support <a id="support"></a>

If you find this project useful, consider giving it a ⭐️! Your support helps bring more attention to the project, allowing us to enhance it even further.

While you're here, feel free to check out my other work: