| 1 | GoTalks 17.03.2026 | |
| 2 | QR code | |
| 3 | How to reach us | |
| 4 | Validation | |
| 6 | Validation types | |
| 7 | Validation types - struct-tag | |
| 8 | Validation types - OpenAPI | |
| 10 | Go 1.25 | |
| 11 | Validation types - CEL | |
| 12 | Validation types - CEL - example | |
| 16 | Validation types - CEL - advanced example | |
| 20 | Validation types - CEL - real world example | |
| 22 | Validation types - CEL - validation for rules | |
| 23 | Validation types - CEL - usage | |
| 25 | Validation types - CEL - source code | |
| 26 | ☕ |



Validation usually refers to checking that:
Official Support for Validation in Go:




type User struct {
Email string `validate:"required,email"`
Age int `validate:"gte=18,lte=99"`
}
validate.RegisterValidation("is-something", func(fl validator.FieldLevel) bool {
return fl.Field().String() == "something"
})






minimum, maximum, enum or pattern can express.

applicant:
celValidations:
- name: "email_basic"
expression: >
email.contains("@")
message: "Email must contain @"
- name: "percentage_passed_check"
expression: >
percentagePassed > 50 && percentagePassed <= 100
message: "Percentage passed must be 50 < x <= 100"


env, err := cel.NewEnv(
ext.NativeTypes(reflect.TypeOf(time.Time{})),
ext.Strings(),
ext.Math(),
cel.VariableDecls(
decls.NewVariable("email", cel.StringType),
decls.NewVariable("percentagePassed", cel.IntType),
),
)


for _, rule := range schema.CELValidations {
ast, issues := env.Compile(rule.Expression)
if issues != nil && issues.Err() != nil {
return issues.Err()
}
prg, err := env.Program(ast)
if err != nil {
return err
}
out, _, err := prg.Eval(map[string]any{
"email": a.Email,
"percentagePassed": a.PercentagePassed,
})


applicant := Applicant{
Email: "test@example.com",
PercentagePassed: 50,
}
output:
Validation failed:
- Percentage passed must be 50 < x <= 100


// +kubebuilder:validation:XValidation:rule= \
// "!has(self.spec.config.default_path)", \
// message="spec.config.default_path is set by ..."
type TCPService struct {
Name string `json:"name"`
// +kubebuilder:validation:Maximum=65535
// +kubebuilder:validation:Minimum=1
Port int `json:"port"`
}


// +kubebuilder:validation:Required
Name string `json:"name"`
// +kubebuilder:validation:Enum=RSA;ECDSA;
Keytype string `json:"keytype,omitempty"`
// +kubebuilder:validation:Pattern=`^[^\s]+$`
ID *string `json:"id,omitempty"`


flowchart LR
n1["User"]
n2["APP"]
n1
n2
n3@{ shape: "hex", label: "Validation" }
n1 --- n3
n3 --- n2


flowchart LR
n1["User"]
n2["APP"]
n1
n2
n3@{ shape: "hex", label: "Validation" }
n1
n3
n3 --- n2
n4@{ shape: "stadium", label: "Admin" }
n4
n3
n5@{ shape: "circle", label: "Use" }
n6@{ shape: "circle", label: "Set" }
n1 --- n5
n5 --- n3
n4 --- n6
n6 --- n3




frontend, backend, specific backend, ...){{.BACKEND}}, {{.NAMESPACE}}, {{.INGRESS}}, {{.SERVICE}}, {{.POD_NAME}}, {{.POD_NAMESPACE}}, {{.POD_IP}})flowchart LR
n1["User"]
n2["APP"]
n1
n2
n3@{ shape: "hex", label: "Validation" }
n1
n3
n3 --- n2
n4@{ shape: "stadium", label: "Admin" }
n4
n3
n5@{ shape: "circle", label: "Use" }
n6@{ shape: "circle", label: "Set" }
n1 --- n5
n5 --- n3
n4 --- n6
n6
n3
n7@{ shape: "hex", label: "Validation for Rules" }
n6 --- n7
n7
n7 --- n3


timeout-server: # name of annotation
section: all # can be all, fronted, backend (default)
namespaces: # we can limit namespace usage
- haproxy-controller
- default
resources: # limit usage to Service, Frontend or Backend names
- <name>
ingresses: # limit usage to specific ingresses
- <name>
order_priority: 100 # order of custom annotations in config.
template: "timeout server {{.}}" # template we can use
type: duration # expected data type for conversion
rule: "value > duration('42s') && value <= duration('42m')"


maxconn:
type: int
rule: "value >= 10 && value <= 1000000"
backend.example.com/maxconn: "1000"


timeouts:
section: backend
template: |
timeout server {{.server}}
timeout server-fin {{.server_fin}}
timeout tarpit {{.tarpit}}
type: json
rule: |
'server' in value && value.server.matches('^[0-9]+[smh]?$') &&
'server_fin' in value && value.server_fin.matches('^[0-9]+[smh]?$') &&
'tarpit' in value && value.tarpit.matches('^[0-9]+[smh]?$')
backend.example.com/timeouts: |
{
"server": "42s",
"server_fin": "10s",
"tarpit": "5s"
}



