cleanenv

repository·master·Indexed 24 days ago

https://github.com/ilyakaznacheev/cleanenv

A minimalistic configuration reading tool for Go that maps configuration files (YAML, JSON, TOML, EDN, ENV) and environment variables directly into structured Go types using struct tags. It supports default values, required fields, runtime updates via the env-upd tag, and custom value parsing through the Setter and Updater interfaces.

Tokens
2.8K
Snippets
8
Records
20
Agent score
80%

What's inside cleanenv

  1. Implement a custom value setter

    master

    To allow a custom type to be populated from an environment variable, implement the Setter interface. The SetValue method should handle the conversion from a string to your custom type.

    type MyField string
    
    func (f *MyField) SetValue(s string) error  {
        if s == "" {
            return fmt.Errorf("field value can't be empty")
        }
        *f = MyField("my field is: " + s)
        return nil
    }
    
    type Config struct {
        Field MyField `env="MY_VALUE"`
    }
  2. Implement custom update logic for configuration

    master

    To execute custom logic (like loading from a remote source) when calling UpdateEnv, implement the Updater interface on your configuration structure. The Update method is called to refresh the fields.

    type Config struct {
        Field string
    }
    
    func (c *Config) Update() error {
        newField, err := SomeCustomUpdate()
        c.Field = newField
        return err
    }
  3. Configure applications using environment variables with cleanenv

    master
    You can use cleanenv to populate a configuration struct directly from environment variables. This allows you to define your application's configuration schema as a Go struct and automatically map environment variables to its fields. This example demonstrates how to use different supported types within a configuration struct to capture various environment values.
  4. Use a custom value setter to parse complex environment variables

    master

    You can implement custom logic to transform environment variable strings into complex types (like slices or custom structs) by defining a SetValue method on your configuration field's type.

    When cleanenv populates your configuration struct, it will call the SetValue method on the field if it exists. This is useful when an environment variable provides a single delimited string (e.g., "admin owner member") but your struct requires a slice (e.g., []string{"admin", "owner", "member"}).

  5. Parse multiple files for configuration

    master
    You can use cleanenv to read configuration from multiple files and merge them into a single Go structure. When multiple files are parsed into the same struct, the values are assigned sequentially, allowing you to split your configuration into logical parts (e.g., database, email, and general settings) while maintaining a unified configuration model.
  6. Integrate cleanenv with the Go flag package

    master

    You can use cleanenv.FUsage to wrap the usage output of the standard Go flag package, allowing you to include environment variable descriptions in your CLI help text.

    // create some config structure
    var cfg config 
    
    // create flag set using `flag` package
    fset := flag.NewFlagSet("Example", flag.ContinueOnError)
    
    // get config usage with wrapped flag usage
    fset.Usage = cleanenv.FUsage(fset.Output(), &cfg, nil, fset.Usage)
    
    fset.Parse(os.Args[1:])
  7. Read configuration from a file and environment variables

    master

    Use cleanenv.ReadConfig to parse a configuration file (e.g., YAML) and then overwrite those values with any matching environment variables. If neither a file nor an environment variable provides a value, the field will use the value specified in the env-default tag.

    import "github.com/ilyakaznacheev/cleanenv"
    
    type ConfigDatabase struct {
        Port     string `yaml:"port" env:"PORT" env-default:"5432"`
        Host     string `yaml:"host" env:"HOST" env-default:"localhost"`
        Name     string `yaml:"name" env:"NAME" env-default:"postgres"`
        User     string `yaml:"user" env:"USER" env-default:"user"`
        Password string `yaml:"password" env:"PASSWORD"`
    }
    
    var cfg ConfigDatabase
    
    err := cleanenv.ReadConfig("config.yml", &cfg)
    if err != nil {
        // handle error
    }
  8. Generate environment variable descriptions for help output

    master
    Use cleanenv.GetDescription to generate a formatted string describing all environment variables in your configuration struct. This is useful for generating help documentation. Use the env-description tag on your struct fields to provide the description text.
  9. Update environment variables at runtime

    master

    To allow certain configuration fields to be refreshed from environment variables while the application is running, mark them with the env-upd tag. You can then call cleanenv.UpdateEnv to update only those specific fields.

    import "github.com/ilyakaznacheev/cleanenv"
    
    type ConfigRemote struct {
        Port     string `env:"PORT" env-upd`
        Host     string `env:"HOST" env-upd`
        UserName string `env:"USERNAME"`
    }
    
    var cfg ConfigRemote
    
    cleanenv.ReadEnv(&cfg)
    
    // ... some actions in-between
    
    err := cleanenv.UpdateEnv(&cfg)
    if err != nil {
        // handle error
    }
  10. Read environment variables only

    master

    If you do not want to use configuration files, use cleanenv.ReadEnv to populate your configuration structure directly from environment variables.

    import "github.com/ilyakaznacheev/cleanenv"
    
    type ConfigDatabase struct {
        Port     string `env:"PORT" env-default:"5432"`
        Host     string `env:"HOST" env-default:"localhost"`
        Name     string `env:"NAME" env-default:"postgres"`
        User     string `env:"USER" env-default:"user"`
        Password string `env:"PASSWORD"`
    }
    
    var cfg ConfigDatabase
    
    err := cleanenv.ReadEnv(&cfg)
    if err != nil {
        // handle error
    }