flatpack

package module
v0.0.0-...-50e0727 Latest Latest
Warning

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

Go to latest
Published: Jun 28, 2018 License: MIT Imports: 9 Imported by: 0

README

What is it?

Flatpack is a 12-factor style configuration mechanism for Go programs. It reads data from the process environment and "splats" it into a struct of your choice. You benefit from Go's type safety without writing boilerplate config-loading code; your users never need to touch a config file; you get to spend your time on features that matter.

Build Status Coverage Status

How do I use it?

Populate the environment with some inputs that you want to convey to your app.

export DATABASE_HOST=db1.example.com
export DATABASE_PORT=1234
export WIDGET_FACTORY=jumbo

Next, define your configuration as a plain old Go struct, potentially with nested structs to represent hierarchy. Ask flatpack to unmarshal the environment into your data structure. If you want flatpack to ignore any of the fields, mark them with a flatpack:"ignore" field tag.

import (
    "github.com/xeger/flatpack"
)

type Config struct {
    Database struct {
        Host string
        Port int
        // Bad idea to mix config with runtime state!
        // We're doing it anyway to showcase the ignore tag.
        Conn sql.Connection `flatpack:"ignore"`
    }

    WidgetFactory string
}

func main() {
    config = Config{}
    err := flatpack.Unmarshal(&config)
}

If Unmarshal returns no errors, your config is available and your app is ready to go!

Why should I use it?

Flatpack's goals are to:

  1. Encourage the use of plain old Go data structures to specify configuration and represent it in-memory.
  2. Decouple the actual reading of config data from validation, propagation across the app, data binding, and other concerns.
  3. Transparently support various repositories for configuration data, e.g. loading a .env file during development, but reading keys from a Consul or Etcd agent when running in production.

Details

Flatpack uses the reflect package to recurse through your configuration struct. As it goes, it maintains a list of field names that it used to arrive at its present location. This list of field names is transformed into an underscore-delimited string like so:

  • Foo.Bar becomes FOO_BAR
  • Foo.Bar.BazQuux becomes FOO_BAR_BAZ_QUUX

(Yes, this means that Foo.BarBaz and FooBar.Baz will both be populated from the same environment variable; don't do that!)

If the environment variable is defined, flatpack parses its value and coerces it to the data type of that field. Supported data types are booleans, numbers, strings, and slices of any of those. If a coercion fails, flatpack returns an error and your app exits with a useful message about what's wrong in the config.

As a coup de grâce, flatpack calls Validate() on your configuration object if it defines that method, giving you a chance to validate the finer points of your configuration or log a startup message with config details.

What Next?

The flatpack.Getter interface allows us to load data from sources other than the environment; it might make sense to build support for HTTP key/value stores directly into the library.

On the other hand, I like the idea of using the process environment to decouple the producer of config data from the consumer; it produces a naturally-portable app. Tools like envconsul can deal with the k/v store on behalf of my app.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Unmarshal

func Unmarshal(dest interface{}) error

Unmarshal reads configuration data from the package's DataSource into a struct.

This is the singleton/package-level interface to flatpack, for applications that want to use the default data source (process environment) or set a process-wide data source at startup.

NOTE: flatpack currently lacks a public non-singleton interface, but it would be easy to add by simply exporting flatpack.new() and declaring an Unmarshaller interface.

Types

type BadType

type BadType struct {
	Name Key
	Kind reflect.Kind
	// contains filtered or unexported fields
}

BadType is an error that provides information about invalid types encountered while unmarshalling.

func (*BadType) Error

func (e *BadType) Error() string

type BadValue

type BadValue struct {
	Name  Key
	Cause error
	// contains filtered or unexported fields
}

BadValue is an error that provides information about malformed values encountered while unmarshalling.

func (*BadValue) Error

func (e *BadValue) Error() string

type Getter

type Getter interface {
	Get(name Key) (string, error)
}

Getter represents a read-only repository of key/value pairs where the keys are ordered sequences of strings and the values are strings. It's analogous to a map[Key]string, but the data may be retrieved from a network or filesystem source and the structured key name may be treated as an indicator of hierarchy or containment within the data source, e.g. URL hierarchy on an HTTP k/v store, or directory hierarchy on a filesystem-based store.

var DataSource Getter = &processEnvironment{os.LookupEnv}

DataSource is the single source of configuration used for all calls to flatpack's singleton interface. When someone calls flatpack.Unmarshal(), the data comes from this source.

By default, DataSource points to the process environment.

type Key

type Key []string

Key is an ordered sequence of struct field names.

func (Key) AsEnv

func (k Key) AsEnv() string

AsEnv returns this key formatted in a way that is suitable for insertion in the process environment.

func (Key) String

func (k Key) String() string

String returns this key formatted as if were a Go expression to access fields of a struct, i.e. a list of dot-separated identifiers.

type NoReflection

type NoReflection struct {
	Name Key
}

NoReflection is an error that indicates something went wrong when reflecting on an unmarshalling target. Generally, this is caused by trying to unmarshal into a struct that has unexported fields (i.e. whose names begin with a lower-case letter).

To avoid this error, either remove the unexported fields from your struct or mark them with the flatpack:"ignore" field tag.

func (*NoReflection) Error

func (e *NoReflection) Error() string

type Validater

type Validater interface {
	Validate() error
}

Validater represents an object that knows how to validate itself. If the object you pass to Unmarshal implements this interface, flatpack will call it for you and return the error if anything fails to validate.

Note that this is a ValidatER (a thing that can Validate itself), not a ValidatOR (a thing that knows how to validate other things).

Jump to

Keyboard shortcuts

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