Help us shape the future of Go! Take the 2026 Go Developer Survey

typedcfg

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 15 Imported by: 0

README

typedcfg

Typed configuration snapshots for Go 1.26+: JSON, HTTP, defaults, custom validation, atomic reads and optional polling, with no third-party runtime dependencies in the core package.

package main

import (
    "fmt"
    "github.com/nextpkg/typedcfg"
)

type Config struct {
    Port int `json:"port" default:"8080"`
}
func (c *Config) Validate() error {
    if c.Port < 1 || c.Port > 65535 { return fmt.Errorf("port must be 1..65535") }
    return nil
}
func main() {
    cm := typedcfg.MustLoad[Config]("config.json", typedcfg.WithWatch())
    defer func() { if err := cm.Close(); err != nil { fmt.Println(err) } }()
    fmt.Println(cm.Get().Port)
}

MustLoad panics on startup errors. Load returns errors; LoadContext[T](ctx, path, options...) also binds updates to a context. An empty path loads only defaults. Keep the manager alive for watching and call Get for each operation needing the latest version.

Updates and ownership

WithWatch polls files every second and HTTP URLs every 30 seconds; WithPollInterval adjusts this. Polling re-reads and decodes on each tick, without ETag or unchanged-content skipping. Filesystem events are an optional adapter.

Reload starts a fresh struct, applies default tags, decodes, runs optional validation and the struct's Validate() error, then publishes atomically. Failed reads or invalid values retain the old version; asynchronous failures appear on Errors() (buffer one, excess errors may be dropped). Consume this channel in the application's existing logging loop. Manual and automatic reloads are serialized.

Get returns a shared read-only pointer without copying or allocating: do not modify any reachable field, map, slice or pointer target. Go does not enforce this rule. Snapshot returns a private deep copy for mutation. Sharing one mutable copy between goroutines still requires synchronization. Publication also copies once to detach decoder/validator references. Old snapshots remain valid; retaining them retains their memory.

Configuration must be plain data: channels, functions, unsafe pointers, locks and unexported fields containing non-nil mutable references are rejected. time.Time is supported. Keep runtime caches outside configuration structs. Unexported fields are not loaded by ordinary decoding or preserved across reloads.

Close is idempotent, cancels HTTP reads, stops subscriptions and joins updates; it retains the last snapshot. Custom sources must honor cancellation or bound I/O. Do not call Reload/Close synchronously from a decoder/validator running inside Reload.

Defaults and formats

Core decoding uses encoding/json directly: json tags, JSON numeric types and UnmarshalJSON apply. There is no weak conversion of strings to numbers/durations. For time.Duration use numeric nanoseconds in JSON or a custom type/codec. Explicit zero/false values override defaults; missing fields retain defaults. See defaults for supported tags.

WithCreateIfMissing exclusively creates missing local files from default tags before watching. It never overwrites files or regenerates them after deletion. Creation requires same-filesystem hard links and an encoder for custom codecs. An invalid generated template remains available for editing.

Validate tags are opt-in. The core only calls custom Validate() error and any explicit WithValidation function; it does not silently enable a tag validator.

Optional modules

Install only capabilities used by the application.

Capability Import / API
YAML github.com/nextpkg/typedcfg/adapters/yaml — yaml.Option(), yaml.v3 rules and yaml tags
File events github.com/nextpkg/typedcfg/adapters/filewatch — filewatch.Option(path), fsnotify
Validation tags github.com/nextpkg/typedcfg/validator — validator.Option(), go-playground tags
Multiple sources, environment, CLI advanced — advanced.NewBuilderT
Nacos / Alibaba Cloud MSE github.com/nextpkg/typedcfg/adapters/nacos — nacos.MustLoad[T](address, dataID)
cm := typedcfg.MustLoad[Config]("config.yaml",
    yaml.Option(), filewatch.Option("config.yaml"))

Pass the same path to Load and filewatch.Option. Events debounce for 50ms and survive atomic replacement; polling remains enabled as a fallback. Independent optional modules bring their own dependencies; core go.mod test dependencies are not included in a production core import.

The advanced module retains the former multi-file Load, MustBuild, WithTag, provider/parser, environment and tag-validation behavior through koanf. Its CLI provider lives at github.com/nextpkg/typedcfg/advanced/adapters/cliv3. Nacos retains its managed-client quick start and advanced source integration; it still carries SDK and advanced-module dependencies.

HTTP and extension points

Load accepts an HTTP(S) URL as its path. WithHTTP(HTTPOptions{...}) configures headers, client, timeout and body limit; defaults are 10 seconds and 1MiB. Only 2xx responses are accepted. Redirects must stay on the original scheme/host/port and are limited to ten requests. URL userinfo and fragments are rejected. Headers and the client are copied when loading; request errors omit the full URL so signed query values are not echoed. Select a YAML codec explicitly for YAML URLs. No disk cache, remote writes, environment expansion or credential rotation is provided.

LoadSource[T](ctx, source, options...) accepts a caller-owned byte reader; WithCodec supplies direct decoding/encoding, WithValidation adds validation, and WithSubscription registers notifications plus polling fallback. Registration precedes the initial read and is cleaned up on startup failure.

Documentation

Overview

Package typedcfg loads single-source configurations into atomic snapshots. JSON, HTTP, polling, defaults and custom validation use only the standard library.

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New("configuration manager is closed")

Functions

This section is empty.

Types

type ConfigError

type ConfigError struct {
	// Type categorizes the kind of error that occurred
	Type ErrorType
	// Source identifies where the error originated (file path, provider name, etc.)
	Source string
	// Message provides a human-readable description of the error
	Message string
	// Cause holds the underlying error that triggered this configuration error
	Cause error
}

ConfigError identifies a configuration failure and wraps its underlying cause.

func NewConfigError

func NewConfigError(errType ErrorType, source, message string, cause error) *ConfigError

NewConfigError constructs a categorized error.

func NewParseError

func NewParseError(source, message string, cause error) *ConfigError

NewParseError wraps a source, decoding, or default-value error.

func NewValidationError

func NewValidationError(source, message string, cause error) *ConfigError

NewValidationError wraps a validation error.

func (*ConfigError) Error

func (e *ConfigError) Error() string

Error includes the category, source, message, and underlying cause.

func (*ConfigError) Is

func (e *ConfigError) Is(target error) bool

Is matches another ConfigError by category.

func (*ConfigError) Unwrap

func (e *ConfigError) Unwrap() error

Unwrap returns the underlying cause.

type ConfigManager

type ConfigManager[T any] struct {
	// contains filtered or unexported fields
}

ConfigManager publishes validated snapshots. Get's entire object graph is read-only.

func Load

func Load[T any](path string, opts ...Option) (*ConfigManager[T], error)

Load reads one JSON file or HTTP(S) URL. An empty path loads only defaults. Use LoadContext to bind refresh to an application context and Close to stop it.

func LoadContext

func LoadContext[T any](ctx context.Context, path string, opts ...Option) (*ConfigManager[T], error)

func LoadSource

func LoadSource[T any](ctx context.Context, source Source, opts ...Option) (*ConfigManager[T], error)

LoadSource loads a caller-owned source. It does not close that source.

func MustLoad

func MustLoad[T any](path string, opts ...Option) *ConfigManager[T]

func (*ConfigManager[T]) Close

func (cm *ConfigManager[T]) Close() error

Close cancels in-flight HTTP reads, joins subscriptions and retains the last snapshot.

func (*ConfigManager[T]) Errors

func (cm *ConfigManager[T]) Errors() <-chan error

Errors buffers one asynchronous error; additional errors may be dropped.

func (*ConfigManager[T]) Get

func (cm *ConfigManager[T]) Get() *T

Get returns the shared snapshot without copying. Do not modify any reachable fields, slices, maps or pointers; use Snapshot for a mutable private copy.

func (*ConfigManager[T]) Reload

func (cm *ConfigManager[T]) Reload() error

Reload builds a fresh object and atomically publishes only after validation. Manual and automatic reloads are serialized. Errors preserve the previous version.

func (*ConfigManager[T]) Snapshot

func (cm *ConfigManager[T]) Snapshot() *T

Snapshot deep-copies the current version for independent local modification.

type Decoder

type Decoder func([]byte, any) error

Decoder decodes into a pointer to the configuration, already populated with defaults.

type Encoder

type Encoder func(any) ([]byte, error)

type ErrorType

type ErrorType int

ErrorType categorizes a configuration failure. Loading currently wraps source and decoding failures as ParseFailure and validation failures as ValidationFailure; other categories are available to callers constructing their own ConfigError.

const (
	// ErrorTypeUnknown represents an unclassified error
	ErrorTypeUnknown ErrorType = iota
	// ErrorTypeFileNotFound indicates a configuration file could not be found
	ErrorTypeFileNotFound
	// ErrorTypeParseFailure indicates failure to parse configuration data
	ErrorTypeParseFailure
	// ErrorTypeValidationFailure indicates configuration validation failed
	ErrorTypeValidationFailure
	// ErrorTypeWatchFailure indicates failure in file watching functionality
	ErrorTypeWatchFailure
	// ErrorTypeMergeFailure indicates failure to merge configuration sources
	ErrorTypeMergeFailure
)

func (ErrorType) String

func (et ErrorType) String() string

String returns the category name.

type HTTPOptions

type HTTPOptions = httpconfig.Options

HTTPOptions controls bounded HTTP reads; headers and the client are copied at Load.

type Option

type Option func(*options)

func WithCodec

func WithCodec(decode Decoder, encode Encoder) Option

WithCodec selects direct decoding and optional encoding for default-file creation. Core JSON uses json tags; other codecs define their own tag and conversion rules.

func WithCreateIfMissing

func WithCreateIfMissing() Option

func WithHTTP

func WithHTTP(opts HTTPOptions) Option

func WithPollInterval

func WithPollInterval(d time.Duration) Option

func WithSubscription

func WithSubscription(s Subscribe) Option

WithSubscription enables notifications plus periodic refresh as a fallback.

func WithValidation

func WithValidation(fn func(any) error) Option

WithValidation adds validation before the configuration's own Validate method. Use the optional validator adapter to enable validate tags.

func WithWatch

func WithWatch() Option

WithWatch enables periodic refresh (files: 1s, HTTP: 30s). For filesystem events, use the optional filewatch adapter instead.

type Source

type Source func(context.Context) ([]byte, error)

Source reads one complete configuration; it must honor cancellation or bound its I/O.

type Subscribe

type Subscribe func(notify func(error)) (stop func() error, err error)

Subscribe registers change notifications and returns an idempotent cleanup function. It must return promptly, clean up on registration failure and never mutate snapshots.

Directories

Path Synopsis
adapters
filewatch module
nacos module
yaml module
advanced module
Package defaults applies default tags to zero-valued struct fields.
Package defaults applies default tags to zero-valued struct fields.
example
basic command
watch command
internal
validator module

Jump to

Keyboard shortcuts

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