Validation & Constraints¶
BOA provides several ways to validate and constrain parameter values.
Required vs Optional¶
By default, all parameters are required. Mark parameters as optional explicitly:
type Params struct {
Name string // required
Port int `optional:"true"` // optional
Verbose bool `optional:"true"` // optional
}
Allowed Values (Alternatives)¶
Use alts to restrict a parameter to specific values:
type Params struct {
LogLevel string `alts:"debug,info,warn,error"`
Format string `alts:"json,yaml,toml"`
}
This provides:
- Shell completion - Tab completion suggests valid values
- Validation - Invalid values are rejected (when
strictis true, which is the default)
Strict Mode¶
By default, alts enforces validation. To allow any value while still providing completion hints:
type Params struct {
// Validation enforced (default)
LogLevel string `alts:"debug,info,warn,error" strict:"true"`
// Suggestions only, any value accepted
Color string `alts:"red,green,blue" strict:"false"`
}
Min/Max Validation¶
Use min and max tags to constrain values. For numeric types, they validate the value. For strings and slices, they validate the length:
type Params struct {
Port int `descr:"port" min:"1" max:"65535"`
Rate float64 `descr:"rate" min:"0.0" max:"1.0"`
Name string `descr:"name" min:"3" max:"20"`
Retries int `descr:"retries" max:"10"`
Count int `descr:"count" min:"0"`
Tags []string `descr:"tags" min:"1" max:"5"`
}
When a pointer field has min/max tags, validation only triggers when a value is actually provided (nil = no validation).
Pattern Validation¶
Use pattern to validate string fields against a regular expression:
type Params struct {
Name string `descr:"app name" pattern:"^[a-z][a-z0-9-]*$"`
Tag string `descr:"version tag" pattern:"^v[0-9]+\\.[0-9]+\\.[0-9]+$"`
}
Like min/max, pattern validation is skipped for optional pointer fields that are not set.
Conditional Requirements¶
Make parameters conditionally required based on other values using HookContext:
type Params struct {
Mode string
FilePath string `optional:"true"`
URL string `optional:"true"`
}
func main() {
boa.CmdT[Params]{
Use: "app",
InitFuncCtx: func(ctx *boa.HookContext, p *Params, cmd *cobra.Command) error {
// FilePath required when Mode is "file"
ctx.GetParam(&p.FilePath).SetRequiredFn(func() bool {
return p.Mode == "file"
})
// URL required when Mode is "http"
ctx.GetParam(&p.URL).SetRequiredFn(func() bool {
return p.Mode == "http"
})
return nil
},
RunFunc: func(p *Params, cmd *cobra.Command, args []string) {
// ...
},
}.Run()
}
Conditional Visibility¶
Hide parameters entirely based on conditions:
type Params struct {
Debug bool `optional:"true"`
Verbose bool `optional:"true"`
}
func main() {
boa.CmdT[Params]{
Use: "app",
InitFuncCtx: func(ctx *boa.HookContext, p *Params, cmd *cobra.Command) error {
// Verbose flag only visible when Debug is true
ctx.GetParam(&p.Verbose).SetIsEnabledFn(func() bool {
return p.Debug
})
return nil
},
RunFunc: func(p *Params, cmd *cobra.Command, args []string) {
// ...
},
}.Run()
}
Dynamic Alternatives¶
For alternatives that depend on runtime state, use SetAlternatives in a hook:
func (c *Config) InitCtx(ctx *boa.HookContext) error {
// Set alternatives based on available options
envs := []string{"dev", "staging", "prod"}
ctx.GetParam(&c.Environment).SetAlternatives(envs)
ctx.GetParam(&c.Environment).SetStrictAlts(true)
return nil
}
Value Priority¶
When multiple sources provide values, BOA uses this priority:
- CLI flags -
--port 8080 - Environment variables -
PORT=8080 - Root config file - (via
configfiletag at root or PreValidate hook) - Substruct config files - (via
configfiletag in nested structs) - Default values -
default:"8080" - Zero value -
0for int,""for string, etc.
Higher priority sources override lower ones.