Documentation
¶
Overview ¶
Package config loads typed application configuration from environment variables and .env files.
Values are resolved with this precedence, highest first: the process environment, .env.<APP_ENV>.local, .env.local (skipped when APP_ENV=test), .env.<APP_ENV>, .env. Structs are filled with Fill using `env` and `default` struct tags.
LoadSource builds the Source the app reads from (app.Source), Load fills a typed struct from it, Secret keeps sensitive values out of logs and output, and Key parses APP_KEY and derives purpose keys from it.
See https://github.com/AlexGalhardo/vukem/blob/main/docs/configuration.md.
Index ¶
Examples ¶
Constants ¶
const MinKeyLen = 32
MinKeyLen is the minimum APP_KEY length in bytes.
Variables ¶
var ErrKeyMissing = errors.New("config: APP_KEY is not set (run `vukem key:generate`)")
ErrKeyMissing is returned by ParseKey when APP_KEY is empty. Outside production an app boots without a key, and every key-derived feature fails with it.
Functions ¶
func Fill ¶
Fill sets the exported fields of the struct pointed to by dst from src.
A field is read from the key in its `env` tag, falling back to its `default` tag. Struct fields without an `env` tag are filled recursively. Supported kinds: string, bool, ints, uints, floats, time.Duration, []string (comma-separated), *url.URL, Secret and any encoding.TextUnmarshaler. All conversion errors are returned together.
func GenerateKey ¶
func GenerateKey() string
GenerateKey returns a new random APP_KEY value ("base64:..." of 32 bytes).
func Load ¶
Load returns a T filled from src. See Fill.
Example ¶
package main
import (
"fmt"
"time"
"github.com/AlexGalhardo/vukem/config"
)
type MailConfig struct {
Host string `env:"MAIL_HOST" default:"localhost"`
Port int `env:"MAIL_PORT" default:"1025"`
Timeout time.Duration `env:"MAIL_TIMEOUT" default:"10s"`
Password config.Secret `env:"MAIL_PASSWORD"`
}
func main() {
// Apps pass app.Source, loaded from .env files and the process
// environment.
src := config.MapSource(map[string]string{
"MAIL_HOST": "smtp.example.com",
"MAIL_PASSWORD": "hunter2",
})
cfg, err := config.Load[MailConfig](src)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(cfg.Host, cfg.Port, cfg.Timeout)
fmt.Println(cfg.Password, cfg.Password.Reveal() == "hunter2")
}
Output: smtp.example.com 1025 10s [redacted] true
func LookupErr ¶ added in v0.28.0
LookupErr reads key from src like Lookup, and also returns the error of an "@file:" process variable whose file cannot be read when src is a *Source (Lookup then reports the key set and empty). Code that reads configuration outside Load and Fill uses it to fail closed.
Types ¶
type Entry ¶
type Entry struct {
Key string
Value string
// Expand reports whether ${VAR} references in Value must be expanded.
// Single-quoted values are literal.
Expand bool
}
Entry is one KEY=VALUE pair parsed from a .env file.
func ParseEnv ¶
ParseEnv parses .env syntax: KEY=VALUE lines, optional "export " prefix, # comments, single-quoted literals and double-quoted values with escapes (which may span lines).
Example ¶
package main
import (
"fmt"
"strings"
"github.com/AlexGalhardo/vukem/config"
)
func main() {
entries, err := config.ParseEnv(strings.NewReader("# app\nAPP_NAME=Shop\nexport APP_DEBUG=true\n"))
if err != nil {
fmt.Println(err)
return
}
for _, e := range entries {
fmt.Printf("%s=%s\n", e.Key, e.Value)
}
}
Output: APP_NAME=Shop APP_DEBUG=true
type Key ¶
type Key struct {
// contains filtered or unexported fields
}
Key is the decoded application key (APP_KEY). Never use it directly for cryptography: derive a purpose-specific key with Derive.
func ParseKey ¶
ParseKey decodes an APP_KEY in the form "base64:<std base64>" (the prefix is optional) and enforces MinKeyLen.
type Secret ¶
type Secret struct {
// contains filtered or unexported fields
}
Secret holds a sensitive value. Every formatting path (fmt, encoding/json, log/slog) prints "[redacted]"; use Reveal to read the value.
func (Secret) MarshalJSON ¶
MarshalJSON implements json.Marshaler.
func (Secret) MarshalText ¶
MarshalText implements encoding.TextMarshaler.
type Source ¶
type Source struct {
// contains filtered or unexported fields
}
Source is a resolved set of configuration values.
func LoadSource ¶
func LoadSource( fsys fs.FS, getenv func(string) (string, bool), readFile func(string) ([]byte, error), ) (*Source, error)
LoadSource reads .env files from fsys and merges them with the process environment provided by getenv (use os.LookupEnv in production code). readFile resolves "@file:" values, in .env files and in the process environment; nil disables them. A referenced file must hold at most 1 MiB.
func (*Source) EnvSet ¶ added in v0.24.0
EnvSet reports whether APP_ENV was given explicitly (process environment, .env files or the map) with a non-empty value; Env then does not fall back to development.
func (*Source) Lookup ¶
Lookup returns the value for key and whether it is set. The process environment wins over .env files. A process variable set to "@file:<path>" is read from that file (Docker/Kubernetes secrets), like a .env value; when the file cannot be read, Lookup reports the key set with an empty value, and Load and Fill return the error.