env

package
v0.255.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2024 License: Apache-2.0 Imports: 12 Imported by: 0

README

Package env

Working with OS environment variables is beneficial because they provide a simple, uniform, and platform-agnostic way to manage application configurations. By storing configuration settings in the environment, developers can separate code from configuration, promoting codebase portability and reducing the risk of sensitive data leakage.

The env package adheres to the principles of the 12-factor app principle's configuration section and helps making configurations more accessible in your application and providing a structured way to load these configuration values into your application.

Key Features

  • Load environment variables into configuration structure based on its env tags.
  • typesafe environment variable Lookup
  • Support for default values using default or env-default tags.
  • configurable list separator using separator or env-separator tags.
  • Support for required fields using required/require or env-required/env-require tags.
  • Support for configuring what layout we need to use to parse a time from the environment value with env-time-layout/layout
  • Custom parsers for specific types can be registered using the RegisterParser function.
  • Built-in support for loading string, int, float, boolean and time.Duration types.
  • Nested structs are also visited and loaded with environment variables.
  • integrates with frameless/pkg/enum package

Examples

Lookup[T any]: typesafe environment variable Lookup.

package main

func main() {
	val, ok, err := env.Lookup[string]("FOO", env.DefaultValue("foo"))
	_, _, _ = val, ok, err
}

Load[T any](ptr *T) error: Loads environment variables into the struct fields based on the field tags.

package main

import "net/url"

type ExampleAppConfig struct {
	Foo     string        `env:"FOO"`
	Bar     time.Duration `env:"BAR" default:"1h5m"`
	Baz     int           `env:"BAZ" enum:"1;2;3;""`
	Qux     float64       `env:"QUX" required:"true"`
	Quux    MyCustomInt   `env:"QUUX"`
	Quuz    time.Time     `env:"QUUZ" layout:"2006-01-02"`
	Corge   *string       `env:"CORGE" required:"false"`
	BaseURL *url.URL      `env:"BASE_URL"`
	Port    int           `env:"PORT" default:"8080"`
}

func main() {
	var c ExampleAppConfig
	if err := env.Load(&c); err != nil {
		logger.Fatal(nil, "failed to load application config", logging.ErrField(err))
		os.Exit(1)
	}
}

RegisterParser[T any]: Registers custom parsers for specific types.

package main

type MyCustomInt int

var _ = env.RegisterParser(func(envValue string) (MyCustomInt, error) {
	// try parse hex
	v, err := strconv.ParseInt(envValue, 16, 64)
	if err == nil {
		return MyCustomInt(v), nil
	}

	// then let's try parse it as base 10 int
	v, err = strconv.ParseInt(envValue, 10, 64)
	if err == nil {
		return MyCustomInt(v), nil
	}
	return 0, err
})

Documentation

Index

Examples

Constants

View Source
const ErrLoadInvalidData errorkit.Error = "ErrLoadInvalidData"

Variables

This section is empty.

Functions

func Load

func Load[T any](ptr *T) error
Example
package main

import (
	"time"

	"go.llib.dev/frameless/pkg/env"
)

func main() {
	type ExampleAppConfig struct {
		Foo string        `env:"FOO"`
		Bar time.Duration `env:"BAR" default:"1h5m"`
		Baz int           `env:"BAZ" required:"true"`
	}

	var c ExampleAppConfig
	if err := env.Load(&c); err != nil {
		_ = err
	}
}
Example (Enum)
package main

import (
	"go.llib.dev/frameless/pkg/env"
)

func main() {
	type ExampleAppConfig struct {
		Foo string `env:"FOO" enum:"foo;bar;baz;" default:"foo"`
	}

	var c ExampleAppConfig
	if err := env.Load(&c); err != nil {
		_ = err
	}
}
Example (WithDefaultValue)
package main

import ()

func main() {
	type ExampleAppConfig struct {
		Foo string `env:"FOO" default:"foo"`
	}
}
Example (WithEnvKeyBackwardCompatibility)
package main

import (
	"go.llib.dev/frameless/pkg/env"
)

func main() {
	type ExampleAppConfig struct {
		// Foo supports both FOO env key and also OLDFOO env key
		Foo string `env:"FOO,OLDFOO"`
	}

	var c ExampleAppConfig
	if err := env.Load(&c); err != nil {
		_ = err
	}
}
Example (WithTimeLayout)
package main

import (
	"time"
)

func main() {
	type ExampleAppConfig struct {
		Foo time.Time `env:"FOO" layout:"2006-01-02"`
	}
}

func Lookup

func Lookup[T any](key string, opts ...LookupOption) (T, bool, error)
Example
package main

import (
	"go.llib.dev/frameless/pkg/env"
)

func main() {
	val, ok, err := env.Lookup[string]("FOO", env.DefaultValue("foo"))
	_, _, _ = val, ok, err
}

func SetLookup added in v0.193.0

func SetLookup[T any](set *Set, ptr *T, key string, opts ...LookupOption)

SetLookup function registers a Lookup within a specified Set. When 'Set.Parse' is invoked, all the registered lookups will be executed. Unlike the 'Lookup' function, 'SetLookup' doesn't permit missing environment variables without a fallback value and will raise it as an issue.

Types

type LookupOption

type LookupOption interface {
	// contains filtered or unexported methods
}

func DefaultValue

func DefaultValue(val string) LookupOption

func ListSeparator

func ListSeparator[SEP rune | string](sep SEP) LookupOption

func ParseWith added in v0.194.0

func ParseWith[T any](parser ParserFunc[T]) LookupOption
Example
package main

import (
	"fmt"
	"strings"

	"go.llib.dev/frameless/pkg/env"
)

func main() {
	// export FOO=foo:baz
	type Conf struct {
		Foo string
		Bar string
	}
	parserFunc := func(v string) (Conf, error) {
		parts := strings.SplitN(v, ":", 1)
		if len(parts) != 2 {
			return Conf{}, fmt.Errorf("invalid format")
		}
		return Conf{
			Foo: parts[0],
			Bar: parts[1],
		}, nil
	}
	conf, ok, err := env.Lookup[Conf]("FOO", env.ParseWith(parserFunc))
	_, _, _ = conf, ok, err
}

func Required

func Required() LookupOption

func TimeLayout

func TimeLayout(layout string) LookupOption

type ParserFunc added in v0.194.0

type ParserFunc[T any] func(envValue string) (T, error)

type Set added in v0.193.0

type Set struct {
	// contains filtered or unexported fields
}
Example
package main

import (
	"go.llib.dev/frameless/pkg/env"
)

func main() {
	var (
		A bool
		B int
		C string
		D []string
	)

	es := &env.Set{}
	env.SetLookup(es, &A, "A")
	env.SetLookup(es, &B, "B")
	env.SetLookup(es, &C, "C", env.DefaultValue("c-default-value"))
	env.SetLookup(es, &D, "D", env.ListSeparator(","))
	if err := es.Parse(); err != nil {
		panic(err)
	}
}

func (Set) Parse added in v0.193.0

func (es Set) Parse() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL