Manual validation in Go
Go handlers often repeat input validation manually:Constraints on types
In Forst, types can declare exactly what makes data valid. You attach constraints directly to types, and the compiler enforces them at the API boundary and, where possible, at compile time. This keeps validation clear and central—no more scattered checks.- Forst
- Generated Go
- Generated TypeScript
placeOrder runs, the compiler has already proven the shape at compile time where values are known; use ensure (or explicit checks) for dynamic input. Invalid SKUs and quantities never reach your catalog logic.
Forst also lets you define your own rules for types with type guards.
Built-in constraints
Constraints appear in two places:
The same built-in names work in both. For
Result narrowing (Ok, Err) and pointer checks (Nil, Present), see Ensure and narrowing.
Chaining
Constraints chain with dots on the base type. All chained rules must pass:- Forst
- Generated Go
Reference
Use constraints on struct fields, function parameters, and nested shapes. Validation follows the data structure, including deeply nested records.
Nested constraints on an order input, including tags on the payload:
- Forst
- Generated Go
Ok()/Err():Resultdiscriminants; use inensure x is Ok()(Ensure and narrowing)Valid(): reserved placeholder; prefer explicit guardsValue(…): literal refinement in assertion types (advanced)
Structural shapes
Forst shapes use field names (camelCase by convention) and compose like TypeScript interfaces:- Forst
- Generated Go
Caveats
Use ensure for runtime checks today
Constraints on types document the rules. The compiler does not emit automatic parameter checks before your function body yet. Use ensure explicitly inside handlers for runtime validation.
Compile time vs runtime
The compiler proves constraints only where values are known at compile time. Dynamic or untrusted input still needsensure at the boundary.
Wire serialization
By default, shape struct fields lower to unexported Go identifiers with nojson tags. For HTTP or JSON marshaling, pass -export-struct-fields on forst run / forst build, or set compiler.exportStructFields: true in ftconfig.json.
Built-in semantics still maturing
The typechecker does not fully validate every built-in constraint beyond presence wiring.Valid() is a reserved placeholder. Prefer explicit constraints or type guards.
Generated TypeScript types reflect structure only. Client-side validation is your job unless you call the Forst server. See Generate client types § Caveats.
Constraint and emission behavior is still expanding. See the roadmap.
What gets emitted
The compiler lowersensure checks in the function body to plain Go: String.Min(1) becomes a len(field) comparison, Int.Min(1) a numeric comparison, and HasPrefix / Contains call strings.* with an auto-added import.
Try it
From the Forst repository:examples/in/.
Related
Ensure and narrowing
Assert invariants inside functions with
ensure … is ….Type guards
Reusable custom predicates on your domain types.