Go package for defining, parsing, and processing struct tags.
Define known keys, use custom separators, enable dynamic tags, add validators, and run optional processors after parsing.
go get github.com/gaigals/gotags@latestDefault syntax uses ; between tags and : between key/value.
package main
import (
"fmt"
"log"
"github.com/gaigals/gotags"
)
const (
tagKeyRequired = "required"
tagKeyEquals = "eq"
tagKeyGT = "gt"
tagKeyLT = "lt"
)
var (
keyRequired = gotags.NewKey(tagKeyRequired, true, false, nil)
keyEquals = gotags.NewKey(tagKeyEquals, false, false, nil)
keyGT = gotags.NewKey(tagKeyGT, false, false, nil)
keyLT = gotags.NewKey(tagKeyLT, false, false, nil)
)
// Default separator (;), default equals (:).
var settings = gotags.NewTagSettingsDefault(
"validator",
tagProcessor, // Optional - can be nil.
keyRequired,
keyEquals,
keyGT,
keyLT,
)
type User struct {
Name string `validator:"required"`
Age uint `validator:"gt:10;lt:130"`
Country string `validator:"eq:Latvia"`
}
func tagProcessor(field gotags.Field) error {
// Optional: runs after parsing and validation.
// Use it for extra checks, transforms, or side effects.
return nil
}
func main() {
user := User{
Name: "John",
Age: 22,
Country: "Latvia",
}
fields, err := settings.ParseStruct(&user)
if err != nil {
log.Fatalln(err)
}
for _, field := range fields {
fmt.Println(field.Name)
for _, tag := range field.Tags {
fmt.Printf(" %s = %q\n", tag.Key, tag.Value)
}
}
// Name
// required = ""
// Age
// gt = "10"
// lt = "130"
// Country
// eq = "Latvia"
}gotags.NewSettings("validator")
gotags.NewSettings("validator").WithEscapeCharacter('\\')
defaultSettings := gotags.NewTagSettingsDefault("validator", nil, keys...)
defaultSettings.WithEscapeCharacter('\\')
gotags.NewTagSettings("validator", ",", "=", nil, false, keys...)WithProcessor(fn)runs after parsing each field.IncludeUntaggedFields()keeps exported fields without the tag.WithNoKeyExistValidation()allows tags with keys not registered up front.WithEscapeCharacter('\\')enables escape parsing.
var settings = gotags.NewSettings("gotags").
WithCustomSeparators(",", "=").
AddKeys(
gotags.NewKey("required", true, false, nil),
gotags.NewKey("min", false, false, nil),
gotags.NewKey("max", false, false, nil),
)
type User struct {
Name string `gotags:"required,min=2,max=255"`
}var settings = gotags.NewSettings("myTag").
WithNoKeyExistValidation()
type Item struct {
Value string `myTag:"rawValue"`
}
// Tag{Key: "rawValue", Value: ""}Use this when you already have one tag string and do not need
ParseStruct.
Useful in tests, custom loaders, generators, or config-driven parsing.
tag, err := gotags.NewTagFromString("min:2", ":")
escapedTag, err := gotags.NewTagFromStringWithEscape(
`replace=old\,value|new\|value`,
"=",
'\\',
)
// escapedTag.Value == `old\,value|new\|value`Use these when Tag.Value has another parsing layer and you want the same
escape rules as gotags.
parts, err := gotags.SplitWithEscape(
`old\,value|new\|value`,
"|",
'\\',
)
fmt.Println(parts[0])
fmt.Println(parts[1])
// old\,value
// new|valueparts, err := gotags.SplitFirstWithEscape(
`requiredIf:Type\:admin\|user|Role`,
":",
'\\',
)
fmt.Println(parts[0])
fmt.Println(parts[1])
// requiredIf
// Type:admin\|user|RoleEscaping is off by default.
Enable it per TagSettings only when values need parser syntax chars.
It also works with custom separators and custom equals chars.
var validatorSettings = gotags.NewSettings("validator").
WithEscapeCharacter('\\')
var gotagsSettings = gotags.NewSettings("gotags").
WithCustomSeparators(",", "=").
WithEscapeCharacter('\\')
type Rules struct {
Regex string `validator:"regex:^foo\,bar$"`
RegexDots string `validator:"regex:^\d+\.\d+$"`
Replace string `gotags:"replace=old\,value|new\|value"`
RequiredIf string `gotags:"requiredIf=Type:admin\|user|Role"`
}\\=>\- escaped current layer separator is returned unescaped
- escaped current layer equals is returned unescaped
- deeper escapes stay as-is in
Tag.Value:\|,\:,\,,\= - unknown escapes stay as-is:
\d,\w,\. - trailing naked
\returns an error
// Check whether a parsed field contains a specific tag key.
field.HasKey("required")
// Get a tag value by key. Missing keys return an empty string.
field.KeyValue("gt")
// Get both the tag value and whether that key was found.
value, ok := field.KeyValueBool("gt")
// Read the first parsed tag on the field.
tag := field.FirstTag()
// Update the struct field value through reflection.
err := field.SetValue("new value")