Handler
HandlerFunc
type HandlerFunc func(c *Ctx) errorThe base handler type. Every route handler and middleware is a HandlerFunc.
app.Get("/hello", func(c *kruda.Ctx) error {
return c.Text("Hello!")
})MiddlewareFunc
type MiddlewareFunc = HandlerFuncMiddlewareFunc is a type alias for HandlerFunc. They are fully interchangeable.
func MyMiddleware(c *kruda.Ctx) error {
// before handler
err := c.Next()
// after handler
return err
}C[T] — Typed Context
type C[T any] struct {
*Ctx
In T // parsed input from request
}C[T] extends Ctx with a typed In field. The request body, route parameters, and query parameters are automatically parsed and validated into T before the handler runs.
Typed Handler Registration
Package-level generic functions register typed handlers with pre-compiled binding and validation:
func Get[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func Post[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func Put[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func Delete[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func Patch[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)type CreateUserInput struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
}
type User struct {
ID string `json:"id"`
Name string `json:"name"`
}
kruda.Post[CreateUserInput, User](app, "/users", func(c *kruda.C[CreateUserInput]) (*User, error) {
return &User{ID: "1", Name: c.In.Name}, nil
})Short Handlers (no error return)
For prototyping — panics are caught by Recovery middleware:
func GetX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)
func PostX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)
func PutX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)
func DeleteX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)
func PatchX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)Group Typed Handlers
func GroupGet[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func GroupPost[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func GroupPut[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func GroupDelete[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)
func GroupPatch[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)RouteOption
type RouteOption func(*routeConfig)WithDescription
func WithDescription(desc string) RouteOptionSets a route description (used by OpenAPI).
WithTags
func WithTags(tags ...string) RouteOptionSets route tags (used by OpenAPI).
Struct Tag Binding
The typed handler binds request data based on struct tags:
type GetUserInput struct {
ID string `param:"id"` // route parameter :id
Fields string `query:"fields"` // query string ?fields=...
}
type UpdateUserInput struct {
ID string `param:"id"` // route parameter
Name string `json:"name"` // JSON body field
Age int `json:"age"` // JSON body field
}Binding order:
paramtags — from route parametersquerytags — from query stringjsontags — from request bodyheadertags — from request headers
Validation
After binding, validation runs automatically using validate struct tags:
type Input struct {
Name string `json:"name" validate:"required,min=2,max=100"`
Age int `json:"age" validate:"min=0,max=150"`
}Validation failures return HTTP 422 with structured error details.
