Validation
Nimbus provides a VineJS-inspired fluent validation API for validating requests, forms, and models. Define rules as chainable methods, validate structs directly, and use database-backed rules for uniqueness checks.
Fluent schema rules
Define validation schemas using the fluent builder API:
import "github.com/CodeSyncr/nimbus/validation"
func (r *CreateBlogRequest) Rules() validation.Schema {
return validation.Schema{
"title": validation.String().Required().Min(1).Max(255),
"content": validation.String().Required().Min(1).Max(5000),
"email": validation.String().Required().Email(),
"age": validation.Number().Required().Min(18).Max(120),
}
}
String rules
| Method | Description |
|---|---|
Required() | Field must not be empty |
Min(n) | Minimum length |
Max(n) | Maximum length |
Email() | Must be a valid email |
URL() | Must be a valid URL |
Regex(pattern) | Must match regex |
In(values...) | Must be one of the allowed values |
Alpha() | Letters only |
AlphaNum() | Letters and numbers only |
Trim() | Trim whitespace before validation |
Confirmed() | Must match field_confirmation |
Number rules
| Method | Description |
|---|---|
Required() | Field must not be zero |
Min(n) | Minimum value |
Max(n) | Maximum value |
Positive() | Must be greater than 0 |
Between(min, max) | Must be within range |
Database rules
Use Unique() and Exists() for database-backed validation. These query the database using GORM.
func (r *CreateUserRequest) Rules() validation.Schema {
return validation.Schema{
// Check email is unique in users table
"email": validation.String().Required().Email().Unique(validation.UniqueOpts{
Table: "users",
Column: "email",
}),
// Unique with filter (exclude current user during updates)
"email": validation.String().Required().Email().Unique(validation.UniqueOpts{
Table: "users",
Column: "email",
Filter: func(db *gorm.DB) *gorm.DB {
return db.Where("id != ?", currentUserID)
},
}),
// Check role exists in roles table
"role_id": validation.Number().Required().Exists(validation.ExistsOpts{
Table: "roles",
Column: "id",
}),
}
}
Model-level validation
Models can implement SchemaProvider to validate themselves. This is the recommended pattern:
type Todo struct {
database.Model
Title string
Done bool
}
func (t *Todo) Rules() validation.Schema {
return validation.Schema{
"title": validation.String().Required().Min(1).Max(255),
}
}
func (t *Todo) Validate() error {
return validation.ValidateStruct(t)
}
// In a controller:
todo := &models.Todo{Title: strings.TrimSpace(ctx.Request.FormValue("title"))}
if err := todo.Validate(); err != nil {
return ctx.View("form", map[string]any{"error": err.Error()})
}
Request validation in controllers
func (c *BlogController) Store(ctx *http.Context) error {
var req validators.CreateBlogRequest
ve, err := validation.BindAndValidateSchema(ctx, &req)
if ve != nil {
return ve // returns 422 JSON with validation errors
}
if err != nil {
return err
}
blog := &models.Blog{Title: req.Title, Content: req.Content}
if err := database.Get().Create(blog).Error; err != nil {
return err
}
return ctx.JSON(http.StatusCreated, blog)
}
Generating validators
Scaffold a validator with the CLI:
nimbus make:validator Blog
This generates a struct with Rules() and Validate() methods using the fluent API.
Conditional validation
Apply rules conditionally based on another field's value or a custom predicate:
When (field-based)
func (r *CreateUserRequest) Rules() validation.Schema {
return validation.Schema{
"role": validation.String().Required().In("personal", "business", "creator"),
// Only required when role is "business"
"company_id": validation.When("role", "business", validation.String().Required()),
// Only required when role is "creator", with a fallback otherwise
"bio": validation.When("role", "creator", validation.String().Min(10)).
Otherwise(validation.String().Max(500)),
}
}
WhenFn (predicate-based)
func (r *OrderRequest) Rules() validation.Schema {
return validation.Schema{
"shipping_address": validation.WhenFn(
func(data map[string]any) bool {
return data["delivery_type"] == "physical"
},
validation.String().Required().Min(10),
),
}
}
Conditional rules implement the Rule interface and compose naturally with other rules in the schema.