Validation Guide
goopt
provides a powerful and flexible validation system that allows you to ensure the correctness of user input. It’s built on a foundation of composable validator functions that can be used both programmatically and directly within struct tags.
Validator Syntax: Parentheses are required for validators with arguments
The validation system uses a consistent, parenthesis-based syntax for validators with arguments.
// required syntax
`goopt:"validators:minlength(5),maxlength(20)"`
Key Rules:
- Validators with no arguments can omit parentheses (e.g.,
email
oremail()
). - Validators with arguments must use parentheses (e.g.,
minlength(5)
). - Multiple validators are comma-separated (e.g.,
validators:email,minlength(10)
).
Using Built-in Validators
You can apply validators directly in your struct tags or programmatically when defining flags.
In Struct Tags
type Config struct {
// Simple validators
Email string `goopt:"name:email;validators:email"`
Port int `goopt:"name:port;validators:port"`
// Multiple validators (all must pass)
Username string `goopt:"name:username;validators:minlength(3),maxlength(20),alphanumeric"`
// Compositional validators
ID string `goopt:"name:id;validators:oneof(email,regex(^EMP-[0-9]{6}$))"`
}
Programmatically
import "github.com/napalu/goopt/v2/validation"
// During parser creation
parser, err := goopt.NewParserWith(
goopt.WithFlag("email", goopt.NewArg(
goopt.WithValidator(validation.Email()),
)),
)
// Or add validators after the fact
parser.AddFlagValidators("port", validation.Port())
Available Built-in Validators
Here is a reference of the most common built-in validators.
Type Validators
Validator | Struct Tag | Description |
---|---|---|
Integer() |
integer or int |
Validates integer values. |
Float() |
float or number |
Validates floating-point numbers. |
Boolean() |
boolean or bool |
Validates boolean values. |
String Validators
Validator | Struct Tag | Description |
---|---|---|
MinLength(n) |
minlength(n) |
Minimum number of Unicode characters. |
MaxLength(n) |
maxlength(n) |
Maximum number of Unicode characters. |
ByteLength(n) |
bytelength(n) |
Exact length in bytes (for UTF-8). |
AlphaNumeric() |
alphanumeric |
Contains only letters and numbers. |
Identifier() |
identifier |
A valid Go-style identifier. |
NoWhitespace() |
nowhitespace |
Contains no whitespace characters. |
Pattern & Network Validators
Validator | Struct Tag | Description |
---|---|---|
Regex(pattern, desc) |
regex(pattern:...,desc:...) |
Matches a regular expression. desc when supplied can be a message key (for translato^tion) or a literal string |
Email() |
email |
A valid email address format. |
URL(schemes...) |
url(http,https) |
A valid URL, optionally restricted to schemes. |
Hostname() |
hostname |
A valid DNS hostname. |
IP() |
ip |
An IPv4 or IPv6 address. |
Port() |
port |
A valid port number (1-65535). |
Numeric Validators
Validator | Struct Tag | Description |
---|---|---|
Range(min, max) |
range(min,max) |
An inclusive float numeric range. |
IntRange(min, max) |
intrange(min,max) |
An inclusive integer numeric range. |
Min(n) |
min(n) |
A minimum numeric value. |
Max(n) |
max(n) |
A maximum numeric value. |
Collection Validators
Validator | Struct Tag | Description |
---|---|---|
IsOneOf(values...) |
isoneof(val1,val2) |
Value must be one of the given strings. |
FileExtension(exts...) |
fileext(.txt,.md) |
File path must have one of the extensions. |
Compositional Validators
Validator | Struct Tag | Description |
---|---|---|
All(validators...) |
all(...) |
All nested validators must pass (AND logic). |
OneOf(validators...) |
oneof(...) |
At least one nested validator must pass (OR logic). |
Not(validator) |
not(...) |
Negates a validator. |
Creating Custom Validators
For domain-specific rules, you can easily create your own validators.
Important: Custom validators can currently only be used programmatically via WithValidator()
or AddFlagValidators()
. They cannot be referenced by name from a struct tag.
Simple Custom Validator
A validator is just a function that takes a string and returns an error.
import "github.com/napalu/goopt/v2/validation"
// HexColor validates that a string is a valid hex color code (e.g., "#ff0000").
func HexColor() validation.ValidatorFunc {
return func(value string) error {
if !strings.HasPrefix(value, "#") || (len(value) != 4 && len(value) != 7) {
return errors.New("must be a valid hex color like #rgb or #rrggbb")
}
// ... more detailed validation ...
return nil
}
}
Using Custom Validators
You can then add your custom validator to any flag.
parser.AddFlag("color", goopt.NewArg(
goopt.WithDescription("A hex color code for the background"),
goopt.WithValidator(HexColor()),
))
Combining with Built-in Validators
Custom validators are fully composable with built-in ones.
// A validator that requires a non-reserved username.
notReserved := validation.Not(validation.IsOneOf("admin", "root", "system"))
parser.AddFlag("username", goopt.NewArg(
goopt.WithValidators(
validation.MinLength(4), // Built-in
validation.AlphaNumeric(), // Built-in
notReserved, // Custom composed
),
))
Making Custom Validators Translatable
To support internationalization, your custom validators can return translatable errors from the errs
package.
import "github.com/napalu/goopt/v2/errs"
// Define your translatable error key.
var ErrInvalidHexColor = i18n.NewError("validation.invalid_hex_color")
func HexColorI18n() validation.ValidatorFunc {
return func(value string) error {
if !strings.HasPrefix(value, "#") {
// Return a translatable error instead of a standard one.
return ErrInvalidHexColor.WithArgs(value)
}
return nil
}
}
Now, you can provide a translation for validation.invalid_hex_color
in your i18n JSON files,
see Internationalization for details.