Documentation
¶
Overview ¶
Package confx adapts github.com/uchaloop/confmaker to Uber Fx. The application explicitly registers its package configs; confmaker owns ENV parsing, defaults, validation and diagnostics, while confx provides the resulting typed values.
Import github.com/uchaloop/confx for registration and github.com/uchaloop/confmaker when using core options such as WithEnv or WithPrefix.
Registration ¶
fx.New(
confx.Module(),
confx.Provide[postgres.Config]("postgres"),
confx.ProvideNamed[postgres.Config]("replica", confmaker.WithPrefix("REPLICA_POSTGRES_")),
)
Module creates one confmaker.Loader per application and is required once when configs are registered. Provide passes the explicit instance name to the core and provides the result without an Fx tag. ProvideNamed additionally uses that name as the Fx tag name:"<name>". confmaker validates names, derives ENV prefixes and loads the configurations; the adapter handles their registration in Fx.
Lifecycle ¶
Every provided config is loaded during fx.New, including configs with no consumer. Loading errors are available from fx.App.Err and prevent startup. Options returned by Provide and ProvideNamed may be reused across applications; each application has its own loader and config values.
Multiple instances and errors ¶
Use Provide for an untagged value. Two values of the same Go type need distinct Fx identities, even when their ENV prefixes differ. ProvideNamed uses the instance name as that identity:
type Params struct {
fx.In
Primary postgres.Config
Replica postgres.Config `name:"replica"`
}
Inspect construction errors with app.Err(). Core ConfigError diagnostics remain reachable through confmaker.ConfigErrors and errors.As. Missing Module or conflicting Fx providers are adapter or Fx errors, not core config diagnostics. Loaded configs should be treated as read-only, including their maps and slices.
Core library ¶
The core also works without Fx:
cfg, err := confmaker.Load[postgres.Config]("postgres")
Declaring configs, options, the manifest and loading rules are documented in package github.com/uchaloop/confmaker.
Example ¶
Provide makes the config available to constructors. WithEnv stands in for the process environment here; an application calls confx.Module() without it.
package main
import (
"fmt"
"time"
"github.com/uchaloop/confmaker"
"github.com/uchaloop/confx"
"go.uber.org/fx"
)
// StoreConfig is the kind of config a library declares: plain fields, env tags,
// and no knowledge of where the values come from.
type StoreConfig struct {
Host string `env:"HOST,notEmpty"`
Timeout time.Duration `env:"TIMEOUT"`
}
func (c *StoreConfig) SetDefaults() { c.Timeout = 30 * time.Second }
func main() {
env := confmaker.WithEnv(map[string]string{"STORE_HOST": "db:5432"})
app := fx.New(
fx.NopLogger,
confx.Module(env),
confx.Provide[StoreConfig]("store"),
fx.Invoke(func(cfg StoreConfig) {
fmt.Println(cfg.Host, cfg.Timeout)
}),
)
if err := app.Err(); err != nil {
fmt.Println(err)
}
}
Output: db:5432 30s
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Module ¶
Module loads the configs registered by Provide and ProvideNamed through one confmaker.Loader per application, configured by opts. Loading happens once during fx.New, when a constructor or invocation requests a config. Every registration is checked, including unused configs. Loading errors reach fx.App.Err and prevent startup, regardless of registration order.
An application that calls Provide or ProvideNamed must include Module exactly once.
func Provide ¶
Provide registers a config with the required instance name and provides it without an Fx tag. confmaker validates the name and derives its default ENV prefix; confmaker.WithPrefix overrides only the prefix. Module is required. The config is loaded during fx.New even when no constructor consumes it.
func ProvideNamed ¶
ProvideNamed registers a config with the required instance name and provides it with the Fx tag name:"<name>". The name also determines the default prefix; confmaker.WithPrefix can override the prefix. Module is required, and loading happens during fx.New as for Provide.
Example ¶
ProvideNamed provides a second instance of the same type under an Fx tag, with its own prefix.
package main
import (
"fmt"
"time"
"github.com/uchaloop/confmaker"
"github.com/uchaloop/confx"
"go.uber.org/fx"
)
// StoreConfig is the kind of config a library declares: plain fields, env tags,
// and no knowledge of where the values come from.
type StoreConfig struct {
Host string `env:"HOST,notEmpty"`
Timeout time.Duration `env:"TIMEOUT"`
}
func (c *StoreConfig) SetDefaults() { c.Timeout = 30 * time.Second }
func main() {
env := confmaker.WithEnv(map[string]string{
"STORE_HOST": "db:5432",
"REPLICA_STORE_HOST": "replica:5432",
})
type params struct {
fx.In
Primary StoreConfig
Replica StoreConfig `name:"replica"`
}
app := fx.New(
fx.NopLogger,
confx.Module(env),
confx.Provide[StoreConfig]("store"),
confx.ProvideNamed[StoreConfig]("replica", confmaker.WithPrefix("REPLICA_STORE_")),
fx.Invoke(func(p params) {
fmt.Println(p.Primary.Host, p.Replica.Host)
}),
)
if err := app.Err(); err != nil {
fmt.Println(err)
}
}
Output: db:5432 replica:5432
Types ¶
This section is empty.