config_access

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 8, 2024 License: Apache-2.0 Imports: 6 Imported by: 0

README

Config Access

Config Access provides tools for loading, layering and accessing configuration files. It works with any configuration format that can be parsed into a map[string]interface{}, which includes Go's built in JSON parser and the most widely used YAML parsers.

This package provides a small subset of the functionality of larger configuration libraries like Viper, but has a fraction of the upstream dependencies. This package provides the configuration handling functionality for the Granitic microservices framework.

GoDoc for this package can be found here

Loading configuration

Config Access is agnostic of how your configuration is stored and parsed, as long as the result of parsing is a map[string]interface{}. For brevity, Config Access defines a type alias ConfigNode for map[string]interface{}.

For example, a JSON file could be loaded and parsed as:

  var config config_access.ConfigNode

  f, _ := os.Open("/your/config.json")
  b, _ := io.ReadAll(f)

  json.Unmarshal(bytes, &config)

Accessing configuration

Once loaded, Config Access provides a way of recovering individual configuration values while converting them to various Go builtin types through an interface called a Selector. Individual items are accessed using a dot delimited 'path' syntax.

  selector := config_access.NewDefaultSelector(config, true, true)
	
  if cs.PathExists("my.string") {
    s := cs.StringVal("my.string")		
  }

Methods exist to try and interpret configuration values as string, int, float64, bool, slices []interface{} and objects map[string]interface{}.

'Quiet' access

If you do not want to handle errors whenever you attempt to access a configuration value, you can use a QuietSelector that instead of returning an error when encountering a problem or missing value, executes a function that you provide.

This can be used to implement 'fail fast' behaviour by exiting the application on an error or logging the problem. If the function you provide does not exit the application, configuration value methods (e.g. StringVal()) will return the zero value relevant to the type you asked for (nil, "", 0 etc")

  quiet := config_access.NewDeferredErrorQuietSelector(config,
	  func(path string, err error){
		  fmt.printf("Error while trying to load config at %s: %s", path, err.Error())
      })

Layering and merging

Configuration sources can be merged together. The most common use case is to combine some base common configuration with configuration that is specific to a deployment environment.

  var base config_access.ConfigNode
  var prod config_access.ConfigNode

  f, _ := os.Open("/your/base-config.json")
  b, _ := io.ReadAll(f)

  json.Unmarshal(bytes, &base)

  f, _ = os.Open("/your/prod-config.json")
  b, _ = io.ReadAll(f)

  json.Unmarshal(bytes, &prod)
  
  combined := config_access.Merge(base, prod, false)

Injecting configuration

Configuration loaded into a ConfigNode can be used to populate the fields of a struct in one call:

  //Assume config previously loaded into variable config
  type Name struct {
    First string
    Middle []string
    Last string
  }
  
  var name Name

  ca.Populate("orderDetails.recipient", &name, config)

Overriding string values with environment variables

Selectors and QuietSelectors provide a StringOrEnv method where value at a config path will be treated as an environment variable name, if it starts with a $. If the environment variable exists, the value of that environment variable will be returned.

The symbol that defines the start of an environment variable can be overridden by supplying an Opts object as part of the call to StringOrEnv

Documentation

Index

Constants

View Source
const (
	ConfigUnset   = -2
	ConfigUnknown = -1
	ConfigString  = 1
	ConfigArray   = 2
	ConfigMap     = 3
	ConfigBool    = 4
)
View Source
const PathSeparator = "."

Variables

This section is empty.

Functions

func Array

func Array(path string, node ConfigNode, errIfMissing bool) ([]interface{}, error)

Array returns the value of an array of objects at the supplied path. Caution should be used when calling this method as behaviour is undefined for arrays of types other than []interface.

If errIfMissing is set to true, an error will be return if the supplied path does not exist otherwise a nil array without an error will be returned.

func BoolVal

func BoolVal(path string, node ConfigNode) (bool, error)

BoolVal returns the bool value of the bool at the supplied path. An error will be returned if the value is not a JSON bool. Note this method only supports the JSON definition of bool (true, false) not the Go definition (true, false, 1, 0 etc) or extended YAML definitions.

func ConfigType

func ConfigType(value interface{}) int

JSONType determines the apparent JSONType of the supplied Go interface.

func Float64Array added in v1.3.0

func Float64Array(path string, node ConfigNode) ([]float64, error)

Float64Array returns an array of float64s from the value at the supplied path.

An error is returned if there is no value at the supplied path or if the value cannot be interpreted as []float64

func Float64Val

func Float64Val(path string, node ConfigNode) (float64, error)

Float64Val returns the float64 value of the number at the supplied path. An error will be returned if the value is not a number.

func IntArray added in v1.3.0

func IntArray(path string, node ConfigNode) ([]int, error)

IntArray returns an array of int from the value at the supplied path.

An error is returned if there is no value at the supplied path or if the value cannot be interpreted as []int

func IntVal

func IntVal(path string, node ConfigNode) (int, error)

IntVal returns the int value of the number at the supplied path. JSON numbers are internally represented by Go as a float64, so no error will be returned, but data might be lost if the number does not actually represent an int. An error will be returned if the value is not a number or cannot be converted to an int.

func Merge

func Merge(base, additional map[string]interface{}, mergeArrays bool) map[string]interface{}

func MergeArrays

func MergeArrays(a []interface{}, b []interface{}) []interface{}

func PathExists

func PathExists(path string, node ConfigNode) bool

func Populate

func Populate(path string, target interface{}, config ConfigNode) error

Populate sets the fields on the supplied target object using the data at the supplied path. This is achieved using Go's json.Marshal to convert the data back into text JSON and then json.Unmarshal to unmarshal back into the target.

func PopulateFromRoot added in v1.1.0

func PopulateFromRoot(target interface{}, config ConfigNode) error

PopulateFromRoot sets the fields on the supplied target object using the whole supplied config document. This is achieved using Go's json.Marshal to convert the data back into text JSON and then json.Unmarshal to unmarshal back into the target.

func SetField

func SetField(fieldName string, path string, target interface{}, config ConfigNode) error

func StringArray added in v1.3.0

func StringArray(path string, node ConfigNode) ([]string, error)

StringArray returns an array of strings from the value at the supplied path.

An error is returned if there is no value at the supplied path or if the value cannot be interpreted as []string

func StringVal

func StringVal(path string, node ConfigNode) (string, error)

StringVal returns the string value of the string at the supplied path. Does not convert other types to a string, so will return an error if the value is not already a string.

func Value

func Value(path string, node ConfigNode) interface{}

Value returns the value at the supplied path or nil if the path does not exist of points to a null value.

Types

type ConfigMerger

type ConfigMerger interface {
	Merge(base, additional ConfigNode) ConfigNode
}

type ConfigNode

type ConfigNode = map[string]interface{}

func ObjectVal

func ObjectVal(path string, node ConfigNode, errIfMissing bool) (ConfigNode, error)

ObjectVal returns a map representing an object or nil if the path does not exist or points to a null value. An error is returned if the value cannot be interpreted as an object (a key in the configuration that has child keys rather than a value. If errIfMissing is set to true, an error will be return if the supplied path does not exist otherwise a nil array without and error will be returned.

type DefaultSelector

type DefaultSelector struct {
	// contains filtered or unexported fields
}

func (*DefaultSelector) Array

func (dfe *DefaultSelector) Array(path string, o ...Opts) ([]interface{}, error)

func (*DefaultSelector) BoolVal

func (dfe *DefaultSelector) BoolVal(path string, o ...Opts) (bool, error)

func (*DefaultSelector) Config

func (dfe *DefaultSelector) Config() ConfigNode

func (*DefaultSelector) Float64Array added in v1.3.0

func (dfe *DefaultSelector) Float64Array(path string, o ...Opts) ([]float64, error)

func (*DefaultSelector) Float64Val

func (dfe *DefaultSelector) Float64Val(path string, o ...Opts) (float64, error)

func (*DefaultSelector) Flush

func (dfe *DefaultSelector) Flush()

func (*DefaultSelector) IntArray added in v1.3.0

func (dfe *DefaultSelector) IntArray(path string, o ...Opts) ([]int, error)

func (*DefaultSelector) IntVal

func (dfe *DefaultSelector) IntVal(path string, o ...Opts) (int, error)

func (*DefaultSelector) ObjectVal

func (dfe *DefaultSelector) ObjectVal(path string, o ...Opts) (ConfigNode, error)

func (*DefaultSelector) PathExists

func (dfe *DefaultSelector) PathExists(path string) bool

func (*DefaultSelector) StringArray added in v1.3.0

func (dfe *DefaultSelector) StringArray(path string, o ...Opts) ([]string, error)

func (*DefaultSelector) StringOrEnv added in v1.3.0

func (dfe *DefaultSelector) StringOrEnv(path string, o ...Opts) (string, error)

func (*DefaultSelector) StringVal

func (dfe *DefaultSelector) StringVal(path string, o ...Opts) (string, error)

func (*DefaultSelector) Value

func (dfe *DefaultSelector) Value(path string, o ...Opts) interface{}

type DeferredErrorQuietSelector added in v1.2.0

type DeferredErrorQuietSelector struct {
	// contains filtered or unexported fields
}

DeferredErrorQuietSelector does not return errors for missing paths or incompatible types, instead executes a supplied error handling function and returns the appropriate zero value for the requested config item.

func (*DeferredErrorQuietSelector) Array added in v1.2.0

func (dqs *DeferredErrorQuietSelector) Array(path string, o ...Opts) []interface{}

func (*DeferredErrorQuietSelector) BoolVal added in v1.2.0

func (dqs *DeferredErrorQuietSelector) BoolVal(path string, o ...Opts) bool

func (*DeferredErrorQuietSelector) Float64Array added in v1.3.0

func (dqs *DeferredErrorQuietSelector) Float64Array(path string, o ...Opts) []float64

func (*DeferredErrorQuietSelector) Float64Val added in v1.2.0

func (dqs *DeferredErrorQuietSelector) Float64Val(path string, o ...Opts) float64

func (*DeferredErrorQuietSelector) IntArray added in v1.3.0

func (dqs *DeferredErrorQuietSelector) IntArray(path string, o ...Opts) []int

func (*DeferredErrorQuietSelector) IntVal added in v1.2.0

func (dqs *DeferredErrorQuietSelector) IntVal(path string, o ...Opts) int

func (*DeferredErrorQuietSelector) ObjectVal added in v1.2.0

func (dqs *DeferredErrorQuietSelector) ObjectVal(path string, o ...Opts) ConfigNode

func (*DeferredErrorQuietSelector) PathExists added in v1.2.0

func (dqs *DeferredErrorQuietSelector) PathExists(path string) bool

func (*DeferredErrorQuietSelector) StringArray added in v1.3.0

func (dqs *DeferredErrorQuietSelector) StringArray(path string, o ...Opts) []string

func (*DeferredErrorQuietSelector) StringOrEnv added in v1.3.0

func (dqs *DeferredErrorQuietSelector) StringOrEnv(path string, o ...Opts) string

func (*DeferredErrorQuietSelector) StringVal added in v1.2.0

func (dqs *DeferredErrorQuietSelector) StringVal(path string, o ...Opts) string

func (*DeferredErrorQuietSelector) Value added in v1.2.0

func (dqs *DeferredErrorQuietSelector) Value(path string, o ...Opts) interface{}

type MissingPathError

type MissingPathError struct {
	// contains filtered or unexported fields
}

MissingPathError indicates that the a problem was caused by there being no value at the supplied config path

func (MissingPathError) Error

func (mp MissingPathError) Error() string

type Opts added in v1.3.0

type Opts struct {
	// If this value is set, it will be returned instead of an error if there is no value at the requested path
	OnMissing any
	// This function will be used instead of os.GetEnv by functions that read environment variables
	EnvAccessFunc func(string) string
	// If set this string is the prefix that is used to indicate that a value is the name of an environment variable (default is $)
	EnvVarPrefix string
}

Opts defines optional behaviour for accessing and interpreting config values

type QuietSelector added in v1.2.0

type QuietSelector interface {
	PathExists(path string) bool
	Value(path string, o ...Opts) interface{}
	ObjectVal(path string, o ...Opts) ConfigNode
	StringVal(path string, o ...Opts) string
	StringArray(path string, o ...Opts) []string
	IntArray(path string, o ...Opts) []int
	Float64Array(path string, o ...Opts) []float64
	IntVal(path string, o ...Opts) int
	Float64Val(path string, o ...Opts) float64
	Array(path string, o ...Opts) []interface{}
	BoolVal(path string, o ...Opts) bool
	StringOrEnv(path string, o ...Opts) string
}

QuietSelector does not return errors for missing paths or incompatible types

func NewDeferredErrorQuietSelector added in v1.2.0

func NewDeferredErrorQuietSelector(conf Selector, errorFunc func(path string, err error)) QuietSelector

func QuietSelectorFromPathValues added in v1.3.0

func QuietSelectorFromPathValues(pv map[string]interface{}, errorFunc func(path string, err error)) QuietSelector

QuietSelectorFromPathValues creates a new QuietSelector populated with a map of complete paths (e.g. "my.config.path": "value")

type Selector

type Selector interface {
	PathExists(path string) bool
	Value(path string, o ...Opts) interface{}
	ObjectVal(path string, o ...Opts) (ConfigNode, error)
	StringVal(path string, o ...Opts) (string, error)

	// StringOrEnv returns the value at the supplied config path unless that value starts with a $, in which
	// case the $ is stripped and the remainder is used as the argument to os.GetEnv.
	//
	// If the environment variable is not set, an error is returned. The prefix and function for recovering the environment
	// variable can both be overridden in the Opts argument.
	StringOrEnv(path string, o ...Opts) (string, error)
	IntVal(path string, o ...Opts) (int, error)
	Float64Val(path string, o ...Opts) (float64, error)
	Array(path string, o ...Opts) ([]interface{}, error)
	StringArray(path string, o ...Opts) ([]string, error)
	IntArray(path string, o ...Opts) ([]int, error)
	Float64Array(path string, o ...Opts) ([]float64, error)
	BoolVal(path string, o ...Opts) (bool, error)
	Flush()
	Config() ConfigNode
}

func NewDefaultSelector

func NewDefaultSelector(config ConfigNode, errorOnMissingObjectPath, errorOnMissingArrayPath bool) Selector

func NewGraniticSelector

func NewGraniticSelector(config ConfigNode) Selector

func SelectorFromPathValues added in v1.3.0

func SelectorFromPathValues(pathValues map[string]interface{}) Selector

SelectorFromPathValues creates a Selector from a map of config paths (e.g. my.config.path) and their associated values. Empty path values are ignored.

Jump to

Keyboard shortcuts

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