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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}
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.