envelope

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2025 License: MIT Imports: 8 Imported by: 0

README

Envelope

GoDoc Go Report Card

Envelope is a Go library that makes it easy to populate Go structs from environment variables.

Installation

go get git.sr.ht/~eugenetriguba/envelope

Quick Start

package main

import (
    "fmt"
    "log"
    "time"

    "git.sr.ht/~eugenetriguba/envelope"
)

type Config struct {
    Host        string        `env:"HOST"`
    Port        int           `env:"PORT"`
    Debug       bool          `env:"DEBUG"`
    Timeout     time.Duration `env:"TIMEOUT"`
    Database    DatabaseConfig `env:"DB"`
}

type DatabaseConfig struct {
    URL      string `env:"URL"`
    Username string `env:"USERNAME"`
    Password string `env:"PASSWORD"`
}

func main() {
    var config Config
    if err := envelope.LoadFromEnv(&config); err != nil {
        log.Fatalf("Failed to load configuration: %v", err)
    }
    
    fmt.Printf("Configuration: %+v\n", config)
}

Run it with:

export HOST=localhost
export PORT=8080
export DEBUG=true
export TIMEOUT=5s
export DB_URL=postgres://localhost:5432/mydb
export DB_USERNAME=admin
export DB_PASSWORD=secret
go run main.go

Output:

Configuration: {Host:localhost Port:8080 Debug:true Timeout:5s Database:{URL:postgres://localhost:5432/mydb Username:admin Password:secret}}

Tutorial

Basic Usage

Envelope uses struct tags to map environment variables to struct fields. The tag name is env.

type ServerConfig struct {
    Host    string `env:"HOST"`
    Port    int    `env:"PORT"`
}

When LoadFromEnv is used on ServerConfig, it will look for environment variables named HOST and PORT and attempt to parse them into the appropriate types.

Supported Types

Envelope supports these types out of the box:

  • String: string
  • Boolean: bool
  • Integer: int, int8, int16, int32, int64
  • Unsigned integer: uint, uint8, uint16, uint32, uint64
  • Floating point: float32, float64
  • Time: time.Time (RFC3339 format)
  • Duration: time.Duration (e.g., "5s", "1h30m")
  • IP address: net.IP
  • IP network: net.IPNet (CIDR notation)
  • URL: url.URL
  • String slices: []string (comma-separated)
  • Integer slices: []int (comma-separated)
Nested Structs

Envelope supports nested structs with automatic prefixing of environment variables:

type DatabaseConfig struct {
    URL      string `env:"URL"`
    Username string `env:"USERNAME"`
    Password string `env:"PASSWORD"`
}

type AppConfig struct {
    Database DatabaseConfig `env:"DB"`
    LogLevel string         `env:"LOG_LEVEL"`
}

// LoadFromEnv will look for:
// - DB_URL
// - DB_USERNAME
// - DB_PASSWORD
// - LOG_LEVEL

If you don't want prefixing for a nested struct, omit the env tag on that field:

type AppConfig struct {
    Database DatabaseConfig // No env tag
    LogLevel string         `env:"LOG_LEVEL"`
}

// LoadFromEnv will look for:
// - URL
// - USERNAME
// - PASSWORD
// - LOG_LEVEL
Custom Type Parsers

You can register custom parsers for your own types:

type CustomType struct {
    Value string
}

envelope.RegisterTypeParser(reflect.TypeOf(CustomType{}), envelope.TypeParserFunc(
    func(value string) (any, error) {
        return CustomType{Value: value}, nil
    },
))

// Now envelope can parse environment variables into CustomType fields

Furthermore, you can override the default supported type parsers by registering your own instead.

envelope.RegisterTypeParser(reflect.TypeOf(time.Time{}), envelope.TypeParserFunc(
    func(value string) (any, error) {
        return time.Parse("01-02-2006", value)
    },
))

// Now time.Time fields will be parsed using MM-DD-YYYY format
// instead of the default RFC3339 format
Error Handling

Envelope may return the following errors from LoadFromEnv:

  • NotPointerToStructError: When the input is not a pointer to a struct
  • UnsupportedTypeError: When a field has a type that's not supported
  • ParseError: When a value couldn't be parsed into the target type

Errors can be checked using Go's standard errors.As():

err := envelope.LoadFromEnv(&config)
var parseErr *envelope.ParseError
if errors.As(err, &parseErr) {
    fmt.Printf("Failed to parse %s from environment variable %s into %v\n",
        parseErr.Value, parseErr.EnvName, parseErr.TargetType)
}

Reference Documentation

For the full API documentation, see the GoDoc.

Documentation

Overview

Envelope provides functionality to populate Go structs from environment variables.

The main function, LoadFromEnv, takes a pointer to a struct and looks for fields with the `env` tag. It then attempts to load the corresponding environment variables and parse them into the appropriate types.

This package supports a wide range of built-in types and allows for extension through custom type parsers. It also handles nested structs, with the parent field's `env` tag serving as a prefix for all fields in the nested struct.

See the documentation for LoadFromEnv for more details and examples.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LoadFromEnv

func LoadFromEnv(ptr any) error

LoadFromEnv populates a struct with values from environment variables.

The function takes a pointer to a struct and looks for fields with the `env` tag. For each field with an `env` tag, it attempts to load the corresponding environment variable and parse it into the field's type.

Supported types include:

  • string
  • bool
  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • time.Time (RFC3339 format)
  • time.Duration
  • net.IP
  • net.IPNet (CIDR notation)
  • url.URL
  • []string, []int (comma-separated)
  • Nested structs
  • Custom types (via registered type parsers)

For nested structs, the parent field's `env` tag is used as a prefix for all fields in the nested struct. If the parent field doesn't have an `env` tag, no prefix is added.

You can override the default parsers or add support for custom types using RegisterTypeParser. This allows you to customize how environment variable values are converted to specific types, including the built-in types.

Example:

type Config struct {
    Host    string  `env:"HOST"`
    Port    int     `env:"PORT"`
    Timeout time.Duration `env:"TIMEOUT"`
    Server  struct {
        MaxConns int `env:"MAX_CONNS"`
    } `env:"SERVER"`
}

// This would look for environment variables:
// HOST, PORT, TIMEOUT, SERVER_MAX_CONNS

Returns an error if the input is not a pointer to a struct, or if any value cannot be parsed into the corresponding field type.

func RegisterTypeParser

func RegisterTypeParser(t reflect.Type, parser TypeParser)

RegisterTypeParser registers a custom type parser for a specific type.

This allows you to extend the LoadFromEnv function to support additional types beyond the built-in ones. The parser will be called when LoadFromEnv encounters a field of the specified type.

You can also use this function to override the default parsers for built-in types. For example, you could register a custom time.Time parser that uses a different date format than the default RFC3339.

Example:

// Register a custom parser for UserID type
type UserID int64

RegisterTypeParser(reflect.TypeOf(UserID(0)), TypeParserFunc(func(value string) (any, error) {
    id, err := strconv.ParseInt(value, 10, 64)
    if err != nil {
        return nil, err
    }
    return UserID(id), nil
}))

// Override the default time.Time parser to use a custom format
RegisterTypeParser(reflect.TypeOf(time.Time{}), TypeParserFunc(func(value string) (any, error) {
    return time.Parse("2006-01-02", value)
}))

Types

type BaseError

type BaseError struct {
	// Message is a human-readable error description
	Message string
	// Err is the underlying error, if any
	Err error
}

BaseError represents the base error type for the envelope package

func (*BaseError) Error

func (e *BaseError) Error() string

func (*BaseError) Unwrap

func (e *BaseError) Unwrap() error

type NotPointerToStructError

type NotPointerToStructError struct {
	BaseError
	ActualType reflect.Type
}

func (*NotPointerToStructError) Error

func (e *NotPointerToStructError) Error() string

type ParseError

type ParseError struct {
	BaseError
	// FieldName is the name of the field being parsed
	FieldName string
	// EnvName is the name of the environment variable
	EnvName string
	// Value is the string value that could not be parsed
	Value string
	// TargetType is the type that the value could not be parsed into
	TargetType reflect.Type
}

ParseError is returned when a value cannot be parsed into the desired type

func (*ParseError) Error

func (e *ParseError) Error() string

type TypeParser

type TypeParser interface {
	// Parse converts a string value from an environment variable to a value
	// that can be set on a struct field
	Parse(value string) (any, error)
}

TypeParser defines an interface for custom type parsing of values from environment variables

type TypeParserFunc

type TypeParserFunc func(value string) (any, error)

TypeParserFunc is a function type that implements TypeParser

func (TypeParserFunc) Parse

func (f TypeParserFunc) Parse(value string) (any, error)

type UnsupportedTypeError

type UnsupportedTypeError struct {
	BaseError
	// FieldName is the name of the field with the unsupported type
	FieldName string
	// FieldType is the unsupported type
	FieldType reflect.Type
}

UnsupportedTypeError is returned when a field has a type that cannot be parsed

func (*UnsupportedTypeError) Error

func (e *UnsupportedTypeError) Error() string

Jump to

Keyboard shortcuts

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