Documentation ¶
Overview ¶
Package xload is a struct first data loading library. xload provides a simple Loader interface to implement custom loaders and compose them in different ways.
Index ¶
- Variables
- func FlattenMap(m map[string]interface{}, sep string) map[string]string
- func Load(ctx context.Context, v any, opts ...Option) error
- type Concurrency
- type Decoder
- type ErrCast
- type ErrCollision
- type ErrDecode
- type ErrInvalidMapValue
- type ErrInvalidPrefix
- type ErrInvalidPrefixAndKey
- type ErrRequired
- type ErrUnknownFieldType
- type ErrUnknownTagOption
- type FieldTagName
- type Loader
- type LoaderFunc
- type MapLoader
- type Option
Examples ¶
- Load (ArrayDelimiter)
- Load (ConcurrentLoading)
- Load (CustomDecoder)
- Load (CustomLoader)
- Load (CustomTagNames)
- Load (DecodingJSONValue)
- Load (Default)
- Load (ExtendingStructs)
- Load (MapSeparator)
- Load (PrefixLoader)
- Load (Required)
- Load (SkipCollisionDetection)
- Load (Structs)
- Load (TransformFieldName)
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNotPointer is returned when the given config is not a pointer. ErrNotPointer = errors.New("xload: config must be a pointer") // ErrNotStruct is returned when the given config is not a struct. ErrNotStruct = errors.New("xload: config must be a struct") // ErrMissingKey is returned when the key is missing from the tag. ErrMissingKey = errors.New("xload: missing key on required field") )
var SkipCollisionDetection = &applier{f: func(o *options) { o.detectCollisions = false }}
SkipCollisionDetection disables detecting any key collisions while trying to load full keys.
Functions ¶
func FlattenMap ¶
FlattenMap flattens a map[string]interface{} into a map[string]string. Nested maps are flattened using given separator.
func Load ¶
Load loads values into the given struct using the given options. "env" is used as the default tag name. xload.OSLoader is used as the default loader.
Example (ArrayDelimiter) ¶
package main import ( "context" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { // value will be split by |, instead of , // e.g. HOSTS=host1|host2|host3 Hosts []string `env:"HOSTS,delimiter=|"` } var conf AppConf err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (ConcurrentLoading) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `env:"HOST"` Debug bool `env:"DEBUG"` Timeout time.Duration `env:"TIMEOUT"` } var conf AppConf loader := xload.LoaderFunc(func(ctx context.Context, key string) (string, error) { // lookup value from a remote service // NOTE: this function is called for each key concurrently // so make sure it is thread-safe. // Using a pooled client is recommended. return "", nil }) err := xload.Load( context.Background(), &conf, xload.Concurrency(3), // load 3 keys concurrently xload.FieldTagName("env"), loader, ) if err != nil { panic(err) } }
Output:
Example (CustomDecoder) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) type Host string func (h *Host) Decode(val string) error { return nil } func main() { // Custom decoder can be used for any type that // implements the Decoder interface. type AppConf struct { Host Host `env:"HOST"` Debug bool `env:"DEBUG"` Timeout time.Duration `env:"TIMEOUT"` } var conf AppConf err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (CustomLoader) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `env:"HOST"` Debug bool `env:"DEBUG"` Timeout time.Duration `env:"TIMEOUT"` } var conf AppConf loader := xload.LoaderFunc(func(ctx context.Context, key string) (string, error) { // lookup value from somewhere return "", nil }) err := xload.Load( context.Background(), &conf, xload.FieldTagName("env"), loader, ) if err != nil { panic(err) } }
Output:
Example (CustomTagNames) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `custom:"HOST"` Debug bool `custom:"DEBUG"` Timeout time.Duration `custom:"TIMEOUT"` } var conf AppConf err := xload.Load(context.Background(), &conf, xload.FieldTagName("custom")) if err != nil { panic(err) } }
Output:
Example (DecodingJSONValue) ¶
package main import ( "context" "encoding/json" "github.com/gojekfarm/xtools/xload" ) type ServiceAccount struct { ProjectID string `json:"project_id"` ClientID string `json:"client_id"` } func (sa *ServiceAccount) UnmarshalJSON(data []byte) error { type Alias ServiceAccount var alias Alias err := json.Unmarshal(data, &alias) if err != nil { return err } *sa = ServiceAccount(alias) return nil } func main() { // Decoding JSON value can be done by implementing // the json.Unmarshaler interface. // // If using json.Unmarshaler, use type alias to avoid // infinite recursion. type AppConf struct { ServiceAccount ServiceAccount `env:"SERVICE_ACCOUNT"` } var conf AppConf err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (Default) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `env:"HOST"` Debug bool `env:"DEBUG"` Timeout time.Duration `env:"TIMEOUT"` } var conf AppConf err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (ExtendingStructs) ¶
package main import ( "context" "net/url" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type Host struct { URL url.URL `env:"URL"` Telemetry bool `env:"TELEMETRY"` } type DB struct { Host Username string `env:"USERNAME"` Password string `env:"PASSWORD"` } type HTTP struct { Host Timeout time.Duration `env:"TIMEOUT"` } type AppConf struct { DB DB `env:",prefix=DB_"` HTTP HTTP `env:",prefix=HTTP_"` } var conf AppConf err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (MapSeparator) ¶
package main import ( "context" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { // key value pair will be split by :, instead of = // e.g. HOSTS=db:localhost,cache:localhost Hosts map[string]string `env:"HOSTS,separator=:"` } var conf AppConf err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (PrefixLoader) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `env:"HOST"` Debug bool `env:"DEBUG"` Timeout time.Duration `env:"TIMEOUT"` } var conf AppConf err := xload.Load( context.Background(), &conf, xload.PrefixLoader("MYAPP_", xload.OSLoader()), ) if err != nil { panic(err) } }
Output:
Example (Required) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `env:"HOST,required"` Debug bool `env:"DEBUG"` Timeout time.Duration `env:"TIMEOUT"` } var conf AppConf // if HOST is not set, Load will return ErrRequired err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (SkipCollisionDetection) ¶
package main import ( "context" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `env:"HOST"` // Hostname is also loaded from HOST, and no error is returned Hostname string `env:"HOST"` Timeout time.Duration `env:"TIMEOUT"` } var conf AppConf err := xload.Load( context.Background(), &conf, xload.SkipCollisionDetection, ) if err != nil { panic(err) } }
Output:
Example (Structs) ¶
package main import ( "context" "github.com/gojekfarm/xtools/xload" ) func main() { type DBConf struct { Host string `env:"HOST"` // will be loaded from DB_HOST Port int `env:"PORT"` // will be loaded from DB_PORT } type HTTPConf struct { Host string `env:"HTTP_HOST"` // will be loaded from HTTP_HOST Port int `env:"HTTP_PORT"` // will be loaded from HTTP_PORT } type AppConf struct { DB DBConf `env:",prefix=DB_"` // example of prefix for nested struct HTTP HTTPConf // example of embedded struct } var conf AppConf err := xload.Load(context.Background(), &conf) if err != nil { panic(err) } }
Output:
Example (TransformFieldName) ¶
package main import ( "context" "strings" "time" "github.com/gojekfarm/xtools/xload" ) func main() { type AppConf struct { Host string `env:"MYAPP_HOST"` Debug bool `env:"MYAPP_DEBUG"` Timeout time.Duration `env:"MYAPP_TIMEOUT"` } var conf AppConf // transform converts key from MYAPP_HOST to myapp.host transform := func(next xload.Loader) xload.LoaderFunc { return func(ctx context.Context, key string) (string, error) { newKey := strings.ReplaceAll(key, "_", ".") newKey = strings.ToLower(newKey) return next.Load(ctx, newKey) } } err := xload.Load( context.Background(), &conf, transform(xload.OSLoader()), ) if err != nil { panic(err) } }
Output:
Types ¶
type Concurrency ¶ added in v0.4.1
type Concurrency int
Concurrency allows customising the number of goroutines to use. Default is 1.
type ErrCast ¶ added in v0.8.1
type ErrCast struct {
// contains filtered or unexported fields
}
ErrCast wraps the actual error that occurred during casting value to go type.
type ErrCollision ¶ added in v0.8.0
type ErrCollision struct {
// contains filtered or unexported fields
}
ErrCollision is returned when key collisions are detected. Collision can happen when two or more fields have the same full key.
func (ErrCollision) Error ¶ added in v0.8.0
func (e ErrCollision) Error() string
func (ErrCollision) Keys ¶ added in v0.8.0
func (e ErrCollision) Keys() []string
Keys returns the collided keys.
type ErrDecode ¶ added in v0.8.1
type ErrDecode struct {
// contains filtered or unexported fields
}
ErrDecode wraps the actual error that occurred during decoding value to go type.
type ErrInvalidMapValue ¶
type ErrInvalidMapValue struct {
// contains filtered or unexported fields
}
ErrInvalidMapValue is returned when the map value is invalid.
func (ErrInvalidMapValue) Error ¶ added in v0.6.0
func (e ErrInvalidMapValue) Error() string
type ErrInvalidPrefix ¶
type ErrInvalidPrefix struct {
// contains filtered or unexported fields
}
ErrInvalidPrefix is returned when the prefix option is used on a non-struct key.
func (ErrInvalidPrefix) Error ¶ added in v0.6.0
func (e ErrInvalidPrefix) Error() string
type ErrInvalidPrefixAndKey ¶ added in v0.4.1
type ErrInvalidPrefixAndKey struct {
// contains filtered or unexported fields
}
ErrInvalidPrefixAndKey is returned when the prefix option is used with a key.
func (ErrInvalidPrefixAndKey) Error ¶ added in v0.6.0
func (e ErrInvalidPrefixAndKey) Error() string
type ErrRequired ¶
type ErrRequired struct {
// contains filtered or unexported fields
}
ErrRequired is returned when a required key is missing.
func (ErrRequired) Error ¶ added in v0.6.0
func (e ErrRequired) Error() string
type ErrUnknownFieldType ¶
type ErrUnknownFieldType struct {
// contains filtered or unexported fields
}
ErrUnknownFieldType is returned when the key type is not supported.
func (ErrUnknownFieldType) Error ¶ added in v0.6.0
func (e ErrUnknownFieldType) Error() string
type ErrUnknownTagOption ¶
type ErrUnknownTagOption struct {
// contains filtered or unexported fields
}
ErrUnknownTagOption is returned when an unknown tag option is used.
func (ErrUnknownTagOption) Error ¶ added in v0.6.0
func (e ErrUnknownTagOption) Error() string
type FieldTagName ¶
type FieldTagName string
FieldTagName allows customising the struct tag name to use.
type LoaderFunc ¶
LoaderFunc is a function that implements Loader.
func PrefixLoader ¶
func PrefixLoader(prefix string, loader Loader) LoaderFunc
PrefixLoader wraps a loader and adds a prefix to all keys.
func SerialLoader ¶
func SerialLoader(loaders ...Loader) LoaderFunc
SerialLoader loads values from multiple loaders. Last non-empty value wins.