Validation
Validate configuration with rules, schemas, constraints, and multiple validation modes.
Confy includes a comprehensive validation engine that checks your configuration against rules, schemas, and custom constraints. Validation can run on startup, on every reload, or on demand.
Quick Start
cfg := confy.New(
confy.WithValidationMode(confy.ValidationModeStrict),
)
// Load sources
cfg.LoadFrom(source)
// Validate
if err := cfg.Validate(); err != nil {
log.Fatal("Configuration invalid:", err)
}Validation Modes
| Mode | Constant | Behavior |
|---|---|---|
| Strict | ValidationModeStrict | Errors on any violation |
| Loose | ValidationModeLoose | Warnings instead of errors for non-critical issues |
| Permissive | ValidationModePermissive | Logs issues but never errors |
| Disabled | ValidationModeDisabled | No validation |
cfg := confy.New(
confy.WithValidationMode(confy.ValidationModeStrict),
)Validation Rules
Add rules to validate individual keys:
validator := confy.NewValidator(confy.ValidatorConfig{
Mode: confy.ValidationModeStrict,
})
validator.AddRule(confy.ValidationRule{
Key: "server.port",
Required: true,
Min: 1,
Max: 65535,
})
validator.AddRule(confy.ValidationRule{
Key: "log.level",
Required: true,
Enum: []any{"debug", "info", "warn", "error"},
})
validator.AddRule(confy.ValidationRule{
Key: "database.host",
Required: true,
Pattern: `^[a-z0-9\.\-]+$`,
})Rule Properties
| Property | Type | Description |
|---|---|---|
Key | string | Configuration key path |
Required | bool | Key must be present |
Min | float64 | Minimum value (numeric) |
Max | float64 | Maximum value (numeric) |
Pattern | string | Regex pattern to match (string) |
Enum | []any | Allowed values |
Custom | func(any) error | Custom validation function |
Validation Schemas
Define schemas for entire configuration sections:
validator.AddSchema(confy.ValidationSchema{
Name: "database",
Path: "database",
Required: []string{"host", "port"},
Properties: map[string]confy.PropertySchema{
"host": {
Type: confy.PropertyTypeString,
Required: true,
Pattern: `^[a-z0-9\.\-]+$`,
},
"port": {
Type: confy.PropertyTypeInteger,
Required: true,
Min: ptrFloat(1),
Max: ptrFloat(65535),
},
"name": {
Type: confy.PropertyTypeString,
Default: "postgres",
},
"ssl_mode": {
Type: confy.PropertyTypeString,
Enum: []any{"disable", "require", "verify-ca", "verify-full"},
},
"pool": {
Type: confy.PropertyTypeObject,
Properties: map[string]confy.PropertySchema{
"max_open": {
Type: confy.PropertyTypeInteger,
Default: 25,
Min: ptrFloat(1),
Max: ptrFloat(1000),
},
"max_idle": {
Type: confy.PropertyTypeInteger,
Default: 5,
},
},
},
},
})Property Types
| Type | Constant | Description |
|---|---|---|
| String | PropertyTypeString | String values |
| Integer | PropertyTypeInteger | Integer values |
| Number | PropertyTypeNumber | Float/decimal values |
| Boolean | PropertyTypeBoolean | Boolean values |
| Array | PropertyTypeArray | Slice/array values |
| Object | PropertyTypeObject | Nested map values |
| Any | PropertyTypeAny | Any type accepted |
Constraint Rules
Constraints validate relationships between multiple config values:
type PortRangeConstraint struct{}
func (c *PortRangeConstraint) Name() string { return "port-range" }
func (c *PortRangeConstraint) Description() string { return "Ports must be 1-65535" }
func (c *PortRangeConstraint) AppliesTo(key string) bool {
return strings.HasSuffix(key, ".port")
}
func (c *PortRangeConstraint) Validate(key string, value any, config map[string]any) error {
if port, ok := value.(int); ok {
if port < 1 || port > 65535 {
return fmt.Errorf("port %d out of range 1-65535", port)
}
}
return nil
}
validator.AddConstraint(&PortRangeConstraint{})Validation Results
The validator returns structured results:
result := validator.ValidateAll(cfg.GetAllSettings())
if !result.Valid {
for _, err := range result.Errors {
log.Printf("ERROR [%s]: %s (key: %s, value: %v)",
err.Severity, err.Message, err.Key, err.Value)
}
}
for _, warn := range result.Warnings {
log.Printf("WARN: %s — key: %s, suggestion: %s",
warn.Message, warn.Key, warn.Suggestion)
}ValidationResult Structure
type ValidationResult struct {
Valid bool
Errors []ValidationError
Warnings []ValidationWarning
Schema string
}
type ValidationError struct {
Key string
Value any
Message string
Severity Severity // SeverityError, SeverityWarning, SeverityInfo
}
type ValidationWarning struct {
Key string
Value any
Message string
Suggestion string
}Validate on Load
Configure automatic validation when config is loaded or reloaded:
validator := confy.NewValidator(confy.ValidatorConfig{
Mode: confy.ValidationModeStrict,
ValidateOnLoad: true,
ValidateOnSet: true,
StrictMode: true,
})| Option | Description |
|---|---|
ValidateOnLoad | Run validation after each LoadFrom or Reload |
ValidateOnSet | Validate individual values on Set calls |
StrictMode | Fail fast on first validation error |
Production Example
func setupValidation(cfg confy.Confy) error {
validator := confy.NewValidator(confy.ValidatorConfig{
Mode: confy.ValidationModeStrict,
ValidateOnLoad: true,
})
// Server config
validator.AddRule(confy.ValidationRule{
Key: "server.port", Required: true, Min: 1, Max: 65535,
})
validator.AddRule(confy.ValidationRule{
Key: "server.host", Required: true,
})
// Database config
validator.AddSchema(confy.ValidationSchema{
Name: "database",
Path: "database",
Required: []string{"host", "port", "name"},
})
// Log level
validator.AddRule(confy.ValidationRule{
Key: "log.level",
Enum: []any{"debug", "info", "warn", "error"},
})
return cfg.Validate()
}How is this guide?