envx

package module
v0.1.15 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2024 License: MIT Imports: 6 Imported by: 13

README

EnvX

Go Reference

EnvX is a zero-dependency, lightweight, Go module that simplifies reading environment variables in your go programs. It reduces the need for boiler plate code when parsing environment variables into desired types.

Installation

go get github.com/emillamm/envx

Usage

Input source

EnvX is just a type definition of func(string)string. It has the same signature as os.Getenv.

var env EnvX = os.Getenv

It can use any function as input, it doesn't have to be os.Getenv.

var env EnvX = func(name string) string {
        switch name {
        case "MY_TIMESTAMP":
            return "2006-01-02T15:04:05+07:00"
        case "MY_INT":
            return "844"
        default:
            return ""
        }
    }
}
Reading variables

EnvX is decorated with helper method for reading string data and parsing it to various types

// Return string
str, err := env.String("MY_STRING").Value()

// Parse and return int
i, err := env.Int("MY_INT").Value()

// Parse and return time.Time using `time.RFC3339` as layout
timestamp, err := env.Time("MY_TIMESTAMP", time.RFC3339).Value()
Errors

A descriptive error is returned if the environment variable doesn't exist. Use errors.Is to check the type of error.

For non-existing environment variables, the returned error wraps ErrEmptyValue.

i, err := env.Int("NON_EXISTING_VAR").Value()

errors.Is(err, ErrEmptyValue) // true

fmt.Println(i)      // 0
fmt.Println(err)    // Error reading environment variable 'NON_EXISTING_VAR' with type 'int': environment variable does not exist

For parsing errors, the returned error wraps ErrInvalidType.

i, err := env.Int("NOT_AN_INT").Value()

errors.Is(err, ErrInvalidType) // true

fmt.Println(i)      // 0
fmt.Println(err)    // Error reading environment variable 'NOT_AN_INT' with type 'int': environment variable could not be converted to expected type
Defaults

.Value() returns the value and an optional error as seen in previous examples.

.Default(...) behaves the same way, except that it falls back to default value instead of returning ErrEmptyValue.

i, err := env.Int("NON_EXISTING_VAR").Default(844)
fmt.Println(i)      // 844
fmt.Println(err)    // <nil>
Deferred error handling

When reading multiple environment variables, it can be cumbersome to check each error along the way. envx.Checkis a helper function that simplifies error handling when reading a batch of environment variables by summarizing all errors into a single error.

func GetConnection(env envx.EnvX) (*Connection, error) {

    // This variable will accumulate errors that arise from reading the following environment variables
    checks := envx.NewChecks()

    // By wrapping each read statement inside a "envx.Check(...)(checks)" expression
    // we are able to capture errors for later processing.
    host := Check(env.String("HOST").Default("localhost"))(checks)
    port := Check(env.Int("PORT").Default(8080))(checks)
    user := Check(env.String("USER").Value())(checks)
    pass := Check(env.String("PASSWORD").Value())(checks)

    // If any errors were encountered, "checks.Err()" will return a descriptive error
    // that summarizes all the underlying errors. Otherwise it returns nil.
    if err := checks.Err(); err != nil {
        return nil, err
    }

    return &Connection{
        Host: host,
        Port: port,
        User: user,
        Pass: pass,
    }, nil
}

Supported types

Review the docs to learn which types EnvX natively supports.

Documentation

Overview

Example (Basic)
// Initialize values
os.Setenv("FOO", "apple")
os.Setenv("BAR", "97")
var env EnvX = os.Getenv

// Returns value of FOO as a string
i, err := env.String("FOO").Value()
fmt.Println(i)   // apple
fmt.Println(err) // <nil>

// Returns value of BAR as an int
j, err := env.Int("BAR").Value()
fmt.Println(j)   // 97
fmt.Println(err) // <nil>

// BAZ doesn't exist, returns ErrEmptyValue wrapped in a descriptive error
k, err := env.Int("BAZ").Value()
fmt.Println(k)   // 0
fmt.Println(err) // Error reading environment variable 'BAZ' with type 'int': environment variable does not exist

// BAZ doesn't exist, returns provided default value
l, err := env.Int("BAZ").Default(88)
fmt.Println(l)   // 88
fmt.Println(err) // <nil>
Output:
apple
<nil>
97
<nil>
0
Error reading environment variable 'BAZ' with type 'int': environment variable does not exist
88
<nil>
Example (Checks)
// This example demonstrates how to use `Checks` to simplify error handling
// when reading multiple environment variables.
package main

import (
	"fmt"
	"os"
)

func GetConnection(env EnvX) (*Connection, error) {

	// This variable will accumulate errors that arise from reading the following environment variables
	checks := NewChecks()

	// By wrapping each read statement inside a "envx.Check(...)(checks)" expression
	// we are able to capture errors for later processing.
	host := Check(env.String("HOST_TEST").Default("localhost"))(checks)
	port := Check(env.Int("PORT_TEST").Default(8080))(checks)
	user := Check(env.String("USER_TEST").Value())(checks)
	pass := Check(env.String("PASSWORD_TEST").Value())(checks)

	// If any errors were encountered, "checks.Err()" will return a descriptive error
	// that summarizes all the underlying errors. Otherwise it returns nil.
	if err := checks.Err(); err != nil {
		return nil, err
	}

	return &Connection{
		Host: host,
		Port: port,
		User: user,
		Pass: pass,
	}, nil
}

func main() {

	connection, err := GetConnection(os.Getenv)
	fmt.Printf("connection: %+v\n", connection)
	fmt.Printf("error: %v\n", err)

	fmt.Println("setting environment variables USER_TEST and PASSWORD_TEST")
	os.Setenv("USER_TEST", "bob")
	os.Setenv("PASSWORD_TEST", "abc123")

	connection, err = GetConnection(os.Getenv)
	fmt.Printf("connection: %+v\n", connection)
	fmt.Printf("error: %v\n", err)

}

type Connection struct {
	Host string
	Port int
	User string
	Pass string
}
Output:
connection: <nil>
error: Unable to read 2 environment variable(s):
Error reading environment variable 'USER_TEST' with type 'string': environment variable does not exist
Error reading environment variable 'PASSWORD_TEST' with type 'string': environment variable does not exist
setting environment variables USER_TEST and PASSWORD_TEST
connection: &{Host:localhost Port:8080 User:bob Pass:abc123}
error: <nil>

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrEmptyValue = errors.New("environment variable does not exist")

ErrEmptyValue is returned as a wrapped error when a non-existing environment variable is read without a default value.

View Source
var ErrInvalidType = errors.New("environment variable could not be converted to expected type")

ErrInvalidType is returned as a wrapped error when an environment variable cannot be parsed as the desired type.

Functions

func Check added in v0.1.9

func Check[T comparable](t T, err error) func(*Checks) T

Check is used for collecting errors when reading multiple environment variables. It should be used as a wrapper around calls to Value.Value or Value.Default after which it will the value will pass through and the error will be intercepted and stored in a Checks. The return type of this function is another function that accepts the Checks that will collect the error and returns the value. This functionality is best described via an example as seen below.

Example
// Initialize env and checks
var env EnvX = os.Getenv
checks := NewChecks()

// Intercepts ErrEmptyValue
str := Check(env.String("NON_EXISTING_STRING").Value())(checks)

// Intercepts ErrInvalidType
os.Setenv("INVALID_INT", "A1Q")
i := Check(env.Int("INVALID_INT").Value())(checks)

fmt.Printf("Returned values str: %#v, i: %v\n", str, i)
fmt.Print(checks.Err())
Output:
Returned values str: "", i: 0
Unable to read 2 environment variable(s):
Error reading environment variable 'NON_EXISTING_STRING' with type 'string': environment variable does not exist
Error reading environment variable 'INVALID_INT' with type 'int': environment variable could not be converted to expected type

Types

type AggregateError added in v0.1.7

type AggregateError struct {
	Errs []error
}

AggregateError is returned when calling Checks.Err. It represents an aggregation of multiple errors.

func (*AggregateError) Error added in v0.1.7

func (e *AggregateError) Error() string

Error returns the error string of the aggregate error with one line per error.

type Checks added in v0.1.9

type Checks []error

Checks represents a temporary aggregation of multiple errors that can be converted to an AggregateError type.

func NewChecks added in v0.1.9

func NewChecks() *Checks

NewChecks allocates a new Checks and returns the pointer.

func (*Checks) Err added in v0.1.9

func (c *Checks) Err() error

Err returns an AggregateError conatining all the errors that were collected while using Check for error handling. If no errors were encountered, this method returns nil.

type EnvX added in v0.1.2

type EnvX func(string) string

EnvX is a type definition that has the same signature as os.Getenv. It exposes several several methods that allows you to read and parse environment variables of different types. Each method returns a Value which in turn provides various methods to retrieve the value.

func (EnvX) Bool added in v0.1.15

func (env EnvX) Bool(name string) *Value[bool]

EnvX.Bool returns a Value of type bool that references the environment variable given by the name. Calling Value.Value will read, parse and return the environment variable.

Example
os.Setenv("FOO_BOOL", "true")

var env EnvX = os.Getenv
var value bool
var err error

value, err = env.Bool("FOO_BOOL").Value()

fmt.Printf("value: %v, error: %v", value, err)
Output:
value: true, error: <nil>

func (EnvX) Duration added in v0.1.9

func (env EnvX) Duration(name string) *Value[time.Duration]

EnvX.Duration returns a Value of type time.Duration that references the environment variable given by the name. Calling Value.Value will read, parse and return the environment variable.

Example
os.Setenv("FOO_DURATION", "5h31m")

var env EnvX = os.Getenv
var value time.Duration
var err error

value, err = env.Duration("FOO_DURATION").Value()

fmt.Printf("value: %v, error: %v", value, err)
Output:
value: 5h31m0s, error: <nil>

func (EnvX) Int added in v0.1.9

func (env EnvX) Int(name string) *Value[int]

EnvX.Int returns a Value of type int that references the environment variable given by the name. Calling Value.Value will read, parse and return the environment variable.

Example
os.Setenv("FOO_INT", "87")

var env EnvX = os.Getenv
var value int
var err error

value, err = env.Int("FOO_INT").Value()

fmt.Printf("value: %v, error: %v", value, err)
Output:
value: 87, error: <nil>

func (EnvX) String added in v0.1.9

func (env EnvX) String(name string) *Value[string]

EnvX.String returns a Value of type string that references the environment variable given by the name. Calling Value.Value will read and return the environment variable. Note that if an empty string is read, it will result in an ErrEmptyValue error.

Example
os.Setenv("FOO_STRING", "apple")

var env EnvX = os.Getenv
var value string
var err error

value, err = env.String("FOO_STRING").Value() // value is apple, err is nil
fmt.Printf("value: %v, error: %v\n", value, err)

value, err = env.String("BAR_STRING").Value() // BAR does not exist: value is "", err is ErrEmptyValue
fmt.Printf("value: %#v, error: %v\n", value, err)
fmt.Printf("error is ErrEmptyValue: %v\n", errors.Is(err, ErrEmptyValue))
Output:
value: apple, error: <nil>
value: "", error: Error reading environment variable 'BAR_STRING' with type 'string': environment variable does not exist
error is ErrEmptyValue: true

func (EnvX) Time added in v0.1.9

func (env EnvX) Time(name string, layout string) *Value[time.Time]

EnvX.Time returns a Value of type time.Time that references the environment variable given by the name. It also accepts a layout string (see time.Layout) to control the parsing format. Calling Value.Value will read, parse and return the environment variable.

Example
os.Setenv("FOO_TIME", "2006-01-02T15:04:05Z")

var env EnvX = os.Getenv
var value time.Time
var err error

value, err = env.Time("FOO_TIME", time.RFC3339).Value()

fmt.Printf("value: %v, error: %v", value, err)
Output:
value: 2006-01-02 15:04:05 +0000 UTC, error: <nil>

type Value added in v0.1.9

type Value[T comparable] struct {
	// Name is the name (or key) of the environment variable
	Name string
	// contains filtered or unexported fields
}

Value represents the name and content of an environment variable after it has been parsed into a desired type.

func (*Value[T]) Default added in v0.1.9

func (v *Value[T]) Default(value T) (t T, err error)

Value.Default reads and parses the environment variable given by Value.Name. If it doesn't exist, it falls back to returning the the provided default value.

func (*Value[T]) Value added in v0.1.9

func (v *Value[T]) Value() (t T, err error)

Value.Value reads and parses the environment variable given by Value.Name.

Jump to

Keyboard shortcuts

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