top

Package envconfig implements a configuration reader which reads each value from an environment variable.

The basic idea is that you define a configuration struct, like this:

var conf struct {
    Addr string
    Port int
    Auth struct {
        Key      string
        Endpoint string
    }
    Partitions []int
    Shards     []struct {
        Name string
        Id   int
    }
}

Once you have that, you need to initialize the configuration:

if err := envconfig.Init(&conf); err != nil {
    log.Fatalln(err)
}

Then it's just a matter of setting the environment variables when calling your binary:

ADDR=localhost PORT=6379 AUTH_KEY=foobar ./mybinary

Layout of the conf struct

Your conf struct must follow the following rules:

- no unexported fields by default (can turn off with Options.AllowUnexported)
- only supported types (no map fields for example)

Naming of the keys

By default, envconfig generates all possible keys based on the field chain according to a flexible naming scheme.

The field chain is how you access your field in the configuration struct. For example:

var conf struct {
    Shard struct {
        Name string
    }
}

With that struct, you access the name field via the chain *Shard.Name*

The default naming scheme takes that and transforms it into the following:

- SHARD_NAME
- shard_name

It can handles more complicated cases, with multiple words in one field name. It needs to be in the correct case though, for example:

var conf struct {
    Cassandra struct {
        SSLCert string
        SslKey  string
    }
}

With that struct, you access the name field via the chain *Cassandra.SSLCert* or *Cassandra.SslKey*

The default naming scheme takes that and transforms it into the following:

- CASSANDRA_SSL_CERT, cassandra_ssl_cert, CASSANDRA_SSLCERT, cassandra_sslcert
- CASSANDRA_SSL_KEY, cassandra_ssl_key, CASSANDRA_SSLKEY, cassandra_sslkey

And, if that is not good enough for you, you always have the option to use a custom key:

var conf struct {
    Cassandra struct {
        Name string `envconfig:"cassandraMyName"`
    }
}

Now envconfig will only ever checks the environment variable _cassandraMyName_.

Content of the variables

There are three types of content for a single variable:

- for simple types, a single string representing the value, and parseable into the type.
- for slices or arrays, a comma-separated list of strings. Each string must be parseable into the element type of the slice or array.
- for structs, a comma-separated list of specially formatted strings representing structs.

Example of a valid slice value:

foo,bar,baz

The format for a struct is as follow:

- prefixed with {
- suffixed with }
- contains a comma-separated list of field values, in the order in which they are defined in the struct

Example of a valid struct value:

type MyStruct struct {
    Name    string
    Id      int
    Timeout time.Duration
}

{foobar,10,120s}

Example of a valid slice of struct values:

{foobar,10,120s},{barbaz,20,50s}

Special case for bytes slices

For bytes slices, you generally don't want to type out a comma-separated list of byte values.

For this use case, we support base64 encoded values.

Here's an example:

var conf struct {
    Data []byte
}

os.Setenv("DATA", "Rk9PQkFS")

This will decode DATA to FOOBAR and put that into conf.Data.

Optional values

Sometimes you don't absolutely need a value. Here's how we tell envconfig a value is optional:

var conf struct {
    Name string `envconfig:"optional"`
    Age int     `envconfig:"-"`
}

The two syntax are equivalent.

Default values

Often times you have configuration keys which almost never changes, but you still want to be able to change them.

In such cases, you might want to provide a default value.

Here's to do this with envconfig:

var conf struct {
    Timeout time.Duration `envconfig:"default=1m"`
}

Combining options

You can of course combine multiple options. The syntax is simple enough, separate each option with a comma.

For example:

var conf struct {
    Timeout time.Duration `envconfig:"default=1m,myTimeout"`
}

This would give you the default timeout of 1 minute, and lookup the myTimeout environment variable.

Supported types

envconfig supports the following list of types:

- bool
- string
- intX
- uintX
- floatX
- time.Duration
- pointers to all of the above types

Notably, we don't (yet) support complex types simply because I had no use for it yet.

Custom unmarshaler

When the standard types are not enough, you will want to use a custom unmarshaler for your types.

You do this by implementing Unmarshaler on your type. Here's an example:

type connectionType uint

const (
    tlsConnection connectionType = iota
    insecureConnection
)

func (t *connectionType) Unmarshal(s string) error {
    switch s {
        case "tls":
            *t = tlsConnection
        case "insecure":
            *t = insecureConnection
        default:
            return fmt.Errorf("unable to unmarshal %s to a connection type", s)
    }

    return nil
}

Imported only in test by 1 package(s)

  1. github.com/hifx/envconfig

Test imports 1 package(s)

  1. github.com/stretchr/testify/require