kruda

package module
v1.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 29, 2026 License: MIT Imports: 37 Imported by: 4

README

Kruda

Fast by default, type-safe by design.

Go Version Go Reference CI codecov

Why Kruda?

  • Typed handlers C[T] — body + param + query parsed into one struct, validated at compile time
  • Auto CRUD — implement ResourceService[T], get 5 REST endpoints
  • Built-in DI — optional, no codegen, type-safe generics
  • Pluggable transport — Wing (Linux, epoll+eventfd), fasthttp, or net/http
  • Minimal deps — Sonic JSON (opt-out via kruda_stdjson), pluggable transport
  • AI-friendly — typed API + 21 examples = AI generates correct code on first try

Quick Start

go get github.com/go-kruda/kruda
package main

import (
    "github.com/go-kruda/kruda"
    "github.com/go-kruda/kruda/middleware"
)

func main() {
    app := kruda.New()
    app.Use(middleware.Recovery(), middleware.Logger())

    app.Get("/ping", func(c *kruda.Ctx) error {
        return c.JSON(kruda.Map{"pong": true})
    })

    app.Listen(":3000")
}

Typed Handlers

type CreateUser struct {
    Name  string `json:"name" validate:"required,min=2"`
    Email string `json:"email" validate:"required,email"`
}

type User struct {
    ID    string `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

kruda.Post[CreateUser, User](app, "/users", func(c *kruda.C[CreateUser]) (*User, error) {
    return &User{ID: "1", Name: c.In.Name, Email: c.In.Email}, nil
})

Auto CRUD

kruda.Resource[User, string](app, "/users", &UserCRUD{db: db})
// Registers: GET /users, GET /users/:id, POST /users, PUT /users/:id, DELETE /users/:id

Dependency Injection

c := kruda.NewContainer()
c.Give(&UserService{})
c.GiveLazy(func() (*DBPool, error) { return connectDB() })
c.GiveNamed("write", &DB{DSN: "primary"})

app := kruda.New(kruda.WithContainer(c))
app.Get("/users", func(c *kruda.Ctx) error {
    svc := kruda.MustResolve[*UserService](c)
    return c.JSON(svc.ListAll())
})

Error Mapping

app.MapError(ErrNotFound, 404, "resource not found")
kruda.MapErrorType[*ValidationError](app, 422, "validation failed")

Coming from Another Framework?

Concept Kruda Gin Fiber Echo stdlib
App kruda.New() gin.Default() fiber.New() echo.New() http.NewServeMux()
Route app.Get("/path", h) r.GET("/path", h) app.Get("/path", h) e.GET("/path", h) mux.HandleFunc("GET /path", h)
Typed handler kruda.Post[In, Out](app, "/path", h)
Group app.Group("/api") r.Group("/api") app.Group("/api") e.Group("/api")
Middleware app.Use(mw) r.Use(mw) app.Use(mw) e.Use(mw)
Context *kruda.Ctx *gin.Context *fiber.Ctx echo.Context http.ResponseWriter, *http.Request
JSON response return &obj, nil c.JSON(200, obj) c.JSON(obj) c.JSON(200, obj) json.NewEncoder(w).Encode(obj)
Path param c.Param("id") c.Param("id") c.Params("id") c.Param("id") r.PathValue("id")
Query param c.Query("q") c.Query("q") c.Query("q") c.QueryParam("q") r.URL.Query().Get("q")
Body binding c.Bind(&v) or C[T].In c.ShouldBindJSON(&v) c.BodyParser(&v) c.Bind(&v) json.NewDecoder(r.Body).Decode(&v)
Auto CRUD kruda.Resource[T, ID](app, "/path", svc)
DI Container.Give() / MustResolve[T](c)

Full migration guides: Gin · Fiber · Echo · stdlib

Benchmarks

Kruda vs Fiber vs Actix Web benchmark

Measured with wrk -t4 -c256 -d5s on Linux i5-13500 (8P cores), GOGC=400.

Test Kruda (Go) Fiber (Go) Actix (Rust) vs Fiber vs Actix
plaintext 846,622 670,240 814,652 +26% +4%
JSON 805,124 625,839 790,362 +29% +2%
db 108,468 107,450 37,373 +1% +190%
fortunes 104,144 106,623 45,078 -2% +131%

Wing transport uses raw epoll + eventfd on Linux — bypasses both fasthttp and net/http. macOS defaults to fasthttp.

Documentation

AI Integration

Kruda includes a built-in MCP server for AI coding assistants (Claude Code, Cursor, Copilot).

# Install CLI
go install github.com/go-kruda/kruda/cmd/kruda@latest

# New projects — .mcp.json included automatically
kruda new myapp

# Existing projects
kruda mcp init        # generates .mcp.json + .cursor/mcp.json
kruda mcp --test      # verify it works
Tool Description
kruda_new Scaffold a new project
kruda_add_handler Generate a typed handler with C[T] pattern
kruda_add_resource Generate a CRUD ResourceService
kruda_list_routes Scan source code and list all registered routes
kruda_suggest_wing Suggest Wing Feather hints for routes
kruda_docs Look up Kruda docs and code examples

Security

See SECURITY.md for our responsible disclosure policy.

import (
    "os"
    "time"

    "github.com/go-kruda/kruda"
    "github.com/go-kruda/kruda/middleware"
    "github.com/go-kruda/kruda/contrib/jwt"
    "github.com/go-kruda/kruda/contrib/ratelimit"
)

app := kruda.New(
    kruda.WithBodyLimit(1024 * 1024), // 1MB body limit
    kruda.WithReadTimeout(10 * time.Second),
)

// Rate limiting — 100 req/min per IP
app.Use(ratelimit.New(ratelimit.Config{
    Max: 100, Window: time.Minute,
    TrustedProxies: []string{"10.0.0.1", "10.0.0.2"},
}))

// Stricter limit on auth endpoints
app.Use(ratelimit.ForRoute("/api/login", 5, time.Minute))

// JWT authentication on protected routes
api := app.Group("/api").Guard(jwt.New(jwt.Config{
    Secret: []byte(os.Getenv("JWT_SECRET")),
}))
Contrib Modules
Module Install Description
contrib/jwt go get github.com/go-kruda/kruda/contrib/jwt JWT sign, verify, refresh (HS256/384/512, RS256)
contrib/ws go get github.com/go-kruda/kruda/contrib/ws WebSocket upgrade, RFC 6455 frames, ping/pong
contrib/ratelimit go get github.com/go-kruda/kruda/contrib/ratelimit Token bucket / sliding window rate limiting
contrib/session go get github.com/go-kruda/kruda/contrib/session Session middleware with pluggable store
contrib/compress go get github.com/go-kruda/kruda/contrib/compress Response compression (gzip, deflate)
contrib/etag go get github.com/go-kruda/kruda/contrib/etag ETag response caching
contrib/cache go get github.com/go-kruda/kruda/contrib/cache Response cache (in-memory, Redis)
contrib/otel go get github.com/go-kruda/kruda/contrib/otel OpenTelemetry tracing
contrib/prometheus go get github.com/go-kruda/kruda/contrib/prometheus Prometheus metrics
contrib/swagger go get github.com/go-kruda/kruda/contrib/swagger Swagger UI HTML
Pre-release Checklist

Run vulnerability scan before every release:

# Install govulncheck (one-time)
go install golang.org/x/vuln/cmd/govulncheck@latest

# Scan root module
govulncheck ./...

# Scan Wing transport module
cd transport/wing && govulncheck ./...

Kruda core has minimal external dependencies (Sonic JSON, fasthttp). Use kruda_stdjson build tag to switch to stdlib JSON. Upgrade to the latest Go patch release for security fixes.

Minimum Go version for zero stdlib vulnerabilities: go1.25.8+

Contributing

Contributions welcome. Please read the Contributing Guide before submitting a PR.

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrAlreadyResponded = fmt.Errorf("kruda: response already sent")

ErrAlreadyResponded is returned when a handler attempts to write a response after one has already been sent. Check with errors.Is(err, ErrAlreadyResponded).

View Source
var ErrBodyTooLarge = errors.New("kruda: request body too large")

ErrBodyTooLarge is returned when the request body exceeds the configured limit.

Functions

func Delete

func Delete[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

Delete registers a typed DELETE handler with pre-compiled binding and validation. Binds from param/query only (no body for DELETE).

func DeleteX

func DeleteX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)

DeleteX registers a short typed DELETE handler (no error return).

func Each

func Each[T any](items []T, fn func(T) error) error

Each applies fn to each item concurrently and returns a joined error of all failures. Waits for ALL invocations to complete before returning.

func Get

func Get[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

Get registers a typed GET handler with pre-compiled binding and validation. Binds from param/query only (no body for GET).

func GetX

func GetX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)

GetX registers a short typed GET handler (no error return). Panics are caught by Recovery middleware. For prototyping and simple endpoints.

func GroupDelete

func GroupDelete[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

GroupDelete registers a typed DELETE handler on a Group.

func GroupGet

func GroupGet[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

GroupGet registers a typed GET handler on a Group.

func GroupPatch

func GroupPatch[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

GroupPatch registers a typed PATCH handler on a Group.

func GroupPost

func GroupPost[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

GroupPost registers a typed POST handler on a Group.

func GroupPut

func GroupPut[In any, Out any](g *Group, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

GroupPut registers a typed PUT handler on a Group.

func MapErrorFunc

func MapErrorFunc(app *App, target error, fn func(error) *KrudaError)

MapErrorFunc registers a custom error transformation function. When a handler returns an error matching target (via errors.Is), fn is called to produce the KrudaError response.

func MapErrorType

func MapErrorType[T error](app *App, statusCode int, message string)

MapErrorType registers a type-based error mapping. Matches any error of type T using errors.As.

This is a free function (not a method on *App) because Go does not support generic methods. Use: kruda.MapErrorType[*MyError](app, 422, "msg")

func MustResolve

func MustResolve[T any](c *Ctx) T

MustResolve is like Resolve but panics on error.

func MustResolveNamed

func MustResolveNamed[T any](c *Ctx, name string) T

MustResolveNamed is like ResolveNamed but panics on error.

func MustUse

func MustUse[T any](c *Container) T

MustUse is like Use but panics on error. Useful in setup/init code where a missing service is a programming error.

func MustUseNamed

func MustUseNamed[T any](c *Container, name string) T

MustUseNamed is like UseNamed but panics on error.

func Need

func Need[T any](c *Ctx, key string) (T, bool)

Need retrieves a typed value from the request context. Returns the value and true if found and castable to T, or zero value and false otherwise. This is a package-level generic function because Go methods cannot have type parameters.

func Parallel

func Parallel(tasks ...func() error) error

Parallel executes all tasks concurrently and waits for ALL to complete. Returns a joined error of all failures, or nil if all succeed.

func Patch

func Patch[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

Patch registers a typed PATCH handler with pre-compiled binding and validation.

func PatchX

func PatchX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)

PatchX registers a short typed PATCH handler (no error return).

func Post

func Post[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

Post registers a typed POST handler with pre-compiled binding and validation.

func PostX

func PostX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)

PostX registers a short typed POST handler (no error return).

func Put

func Put[In any, Out any](app *App, path string, handler func(*C[In]) (*Out, error), opts ...RouteOption)

Put registers a typed PUT handler with pre-compiled binding and validation.

func PutX

func PutX[In any, Out any](app *App, path string, handler func(*C[In]) *Out, opts ...RouteOption)

PutX registers a short typed PUT handler (no error return).

func Race

func Race(ctx context.Context, tasks ...func(context.Context) (any, error)) (any, error)

Race executes all tasks concurrently and returns the result of the first to complete. The context is passed to each task so callers can cancel slower goroutines. Returns (nil, nil) if no tasks are provided.

func Resolve

func Resolve[T any](c *Ctx) (T, error)

Resolve resolves a service of type T from the DI container attached to the current request context.

func ResolveNamed

func ResolveNamed[T any](c *Ctx, name string) (T, error)

ResolveNamed resolves a named instance of type T from the DI container.

func Use

func Use[T any](c *Container) (T, error)

Use resolves a service of type T from the container. Checks singletons first (no cycle detection), then transients, then lazy singletons. Returns (zero, error) if the type is not registered or a factory fails.

func UseNamed

func UseNamed[T any](c *Container, name string) (T, error)

UseNamed resolves a named instance of type T from the container. Returns error if the name is not found or the stored instance cannot be type-asserted to T.

Types

type App

type App struct {
	// contains filtered or unexported fields
}

App is the main framework struct that holds config, router, middleware, hooks, error mappings, transport, and the context pool.

func New

func New(opts ...Option) *App

New creates a new App with default config and applies the provided options. If no Transport option is given, it defaults to Wing (epoll+eventfd) on Linux, fasthttp on macOS, and net/http on Windows.

func Resource

func Resource[T any, ID comparable](app *App, path string, svc ResourceService[T, ID], opts ...ResourceOption) *App

Resource auto-wires 5 REST endpoints from a ResourceService on the App. It registers: GET (list), GET/:id (get), POST (create), PUT/:id (update), DELETE/:id (delete).

func (*App) AfterHandle

func (app *App) AfterHandle(fn HookFunc) *App

AfterHandle registers a hook that fires after the handler returns, before OnResponse. Use for response transformation, caching, or post-processing. Returning an error triggers the error handler.

func (*App) All

func (app *App) All(path string, handler HandlerFunc, opts ...RouteOption) *App

All registers a route on all standard HTTP methods.

func (*App) BeforeHandle

func (app *App) BeforeHandle(fn HookFunc) *App

BeforeHandle registers a hook that fires after middleware but before the final handler. Use for auth checks, permission verification, or request decoration. Returning an error stops the pipeline — the handler is NOT called.

func (*App) Compile

func (app *App) Compile()

Compile freezes the router tree and applies AOT optimizations. Called automatically by Listen(). Useful for benchmarks and tests that call ServeKruda directly without Listen().

func (*App) Delete

func (app *App) Delete(path string, handler HandlerFunc, opts ...RouteOption) *App

Delete registers a DELETE route.

func (*App) Get

func (app *App) Get(path string, handler HandlerFunc, opts ...RouteOption) *App

Get registers a GET route.

func (*App) Group

func (app *App) Group(prefix string) *Group

Group creates a new top-level route group with the given prefix. The group shares the App's global middleware and can add its own scoped middleware via Use() or Guard().

api := app.Group("/api")
api.Get("/users", listUsers)

func (*App) Head

func (app *App) Head(path string, handler HandlerFunc, opts ...RouteOption) *App

Head registers a HEAD route.

func (*App) Listen

func (app *App) Listen(addr string) error

Listen compiles the router, starts the transport in a goroutine, and blocks waiting for SIGINT or SIGTERM to initiate graceful shutdown.

func (*App) MapError

func (app *App) MapError(target error, status int, message string) *App

MapError registers an error-to-HTTP mapping. When a handler returns this error, Kruda auto-responds with the mapped status and message.

func (*App) Module

func (app *App) Module(m Module) *App

Module installs a DI module into the App. If no container is configured, a new one is created automatically. Panics if Install returns an error — module registration failures are considered programming errors. Returns the App for method chaining.

func (*App) OnError

func (app *App) OnError(fn ErrorHookFunc) *App

OnError registers a hook that fires when an error occurs during request processing. Receives the context and the error. Always fires — even if a response was already sent — so logging and metrics hooks work reliably.

func (*App) OnParse

func (app *App) OnParse(fn func(c *Ctx, input any) error) *App

OnParse registers a hook that fires after input parsing but before validation. The hook receives the parsed input as `any` — type-assert to the specific type. Returning an error stops the pipeline (skips validation and handler).

func (*App) OnRequest

func (app *App) OnRequest(fn HookFunc) *App

OnRequest registers a hook that fires when a request arrives, before route matching. Use for logging, request ID injection, rate limiting, or early request validation. Returning an error stops the pipeline — the error handler runs and no routing occurs.

func (*App) OnResponse

func (app *App) OnResponse(fn HookFunc) *App

OnResponse registers a hook that fires after the handler completes (including AfterHandle). Use for response logging, metrics collection, or cleanup. Errors are logged but do not affect the response (it has already been written).

func (*App) OnShutdown

func (app *App) OnShutdown(fn func()) *App

OnShutdown registers a cleanup function to be called during shutdown. Functions are executed in LIFO order (last registered, first called).

func (*App) Options

func (app *App) Options(path string, handler HandlerFunc, opts ...RouteOption) *App

Options registers an OPTIONS route.

func (*App) Patch

func (app *App) Patch(path string, handler HandlerFunc, opts ...RouteOption) *App

Patch registers a PATCH route.

func (*App) Post

func (app *App) Post(path string, handler HandlerFunc, opts ...RouteOption) *App

Post registers a POST route.

func (*App) Put

func (app *App) Put(path string, handler HandlerFunc, opts ...RouteOption) *App

Put registers a PUT route.

func (*App) ServeFast

func (app *App) ServeFast(ctx *fasthttp.RequestCtx)

ServeFast handles a fasthttp request directly, bypassing transport selection. This is the fastest path for fasthttp-based benchmarks and production use.

func (*App) ServeFastHTTP

func (app *App) ServeFastHTTP(ctx interface{})

ServeFastHTTP implements transport.FastHTTPHandler for zero-allocation fasthttp serving.

func (*App) ServeHTTP

func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler for fast net/http path. Uses lightweight adapters and avoids defer overhead.

func (*App) ServeKruda

func (app *App) ServeKruda(w transport.ResponseWriter, r transport.Request)

ServeKruda implements transport.Handler. Includes panic recovery to prevent server crashes from unhandled panics not caught by Recovery middleware.

func (*App) Shutdown

func (app *App) Shutdown(ctx context.Context) error

Shutdown initiates graceful shutdown programmatically (useful for tests). Also runs OnShutdown hooks in LIFO order.

func (*App) Static

func (app *App) Static(prefix, root string, opts ...StaticOption) *App

Static serves files from a directory.

app.Static("/assets", "./public")
app.Static("/", "./dist")  // SPA fallback

func (*App) StaticFS

func (app *App) StaticFS(prefix string, fsys fs.FS, opts ...StaticOption) *App

StaticFS serves files from an fs.FS (embed support).

//go:embed dist
var distFS embed.FS
app.StaticFS("/", distFS)

func (*App) Use

func (app *App) Use(middleware ...HandlerFunc) *App

Use appends global middleware to the App. Middleware added via Use() only applies to routes registered AFTER this call. Routes registered before Use() will not have this middleware in their chain.

func (*App) Validator

func (app *App) Validator() *Validator

Validator returns the app's Validator instance, creating one if needed. Use this to register custom rules or override messages.

type C

type C[T any] struct {
	*Ctx
	In T // parsed input from request
}

C is the generic typed context that embeds *Ctx with a parsed input field. c.In contains the parsed + validated input from all sources (param, query, body).

type Config

type Config struct {
	ReadTimeout  time.Duration // default: 30s
	WriteTimeout time.Duration // default: 30s
	IdleTimeout  time.Duration // default: 120s

	BodyLimit   int // default: 4MB
	HeaderLimit int // default: 8KB

	ShutdownTimeout time.Duration // default: 10s

	Transport     transport.Transport
	TransportName string // "wing" (default on Linux), "fasthttp" (default on macOS), "nethttp" (default on Windows)
	TLSCertFile   string
	TLSKeyFile    string
	HTTP3         bool

	// TrustProxy enables trusting X-Forwarded-For/X-Real-IP headers. Default: false.
	TrustProxy bool

	JSONEncoder func(v any) ([]byte, error)
	JSONDecoder func(data []byte, v any) error

	// JSONStreamEncoder encodes v as JSON into the provided buffer.
	// When non-nil, c.JSON() uses this with a sync.Pool'd bytes.Buffer
	// instead of JSONEncoder, eliminating one allocation per response.
	// Set automatically when using the default encoder; cleared by WithJSONEncoder.
	JSONStreamEncoder func(buf *bytes.Buffer, v any) error

	Security        SecurityConfig
	SecurityHeaders bool
	PathTraversal   bool
	DevMode         bool

	Logger       *slog.Logger
	ErrorHandler func(c *Ctx, err *KrudaError)
	Validator    *Validator

	// Views is the template engine for c.Render(). Nil = c.Render() returns error.
	Views ViewEngine
	// contains filtered or unexported fields
}

Config holds the server configuration.

type Container

type Container struct {
	// contains filtered or unexported fields
}

Container is the dependency injection container. Stores services keyed by reflect.Type with three lifetime models: singleton (Give), transient (GiveTransient), and lazy singleton (GiveLazy). Thread-safe via sync.RWMutex.

func NewContainer

func NewContainer() *Container

NewContainer creates a new empty DI container.

func (*Container) Give

func (c *Container) Give(instance any) error

Give registers a singleton instance keyed by its reflect.Type. Returns error if instance is nil or type already registered.

func (*Container) GiveAs

func (c *Container) GiveAs(instance any, ifacePtr any) error

GiveAs registers a singleton keyed by the interface type extracted from ifacePtr. ifacePtr must be a pointer to an interface (e.g. (*MyInterface)(nil)).

func (*Container) GiveLazy

func (c *Container) GiveLazy(factory any) error

GiveLazy registers a factory that runs once on first Use[T]() call. Subsequent calls return the cached result. If the factory returns an error, the result is not cached and the factory will be retried on the next call.

func (*Container) GiveNamed

func (c *Container) GiveNamed(name string, instance any) error

GiveNamed registers a named singleton instance. Multiple instances of the same type can be registered with different names. The instance participates in lifecycle (OnInit/OnShutdown) and health checks.

func (*Container) GiveTransient

func (c *Container) GiveTransient(factory any) error

GiveTransient registers a factory that creates a new instance on every Use[T]() call. factory must be a function with signature func() (T, error) or func() T.

func (*Container) InjectMiddleware

func (c *Container) InjectMiddleware() HandlerFunc

InjectMiddleware returns a middleware that makes the container available in the request context via c.Set("container", container). Use with app.Use(container.InjectMiddleware()) to enable Resolve[T]() lookups from the context locals (in addition to app-level fallback).

func (*Container) Shutdown

func (c *Container) Shutdown(ctx context.Context) error

Shutdown calls OnShutdown on all services in initOrder that implement Shutdowner, in reverse registration/resolution order. All errors are collected and returned via errors.Join.

func (*Container) Start

func (c *Container) Start(ctx context.Context) error

Start calls OnInit on all services in initOrder that implement Initializer, in registration/resolution order. If any OnInit fails, already-initialized services that implement Shutdowner get OnShutdown called for cleanup in reverse order.

type Cookie struct {
	Name     string
	Value    string
	Path     string
	Domain   string
	MaxAge   int
	Secure   bool
	HTTPOnly bool
	SameSite http.SameSite
}

Cookie represents an HTTP cookie.

type Ctx

type Ctx struct {
	// contains filtered or unexported fields
}

Hot fields accessed every request are packed into the first cache lines to minimize cache misses on the hot path.

func (*Ctx) AddHeader

func (c *Ctx) AddHeader(key, value string) *Ctx

AddHeader appends a value to a response header without replacing existing values. Supports multi-value headers like Vary, Cache-Control. Chainable. Fixed-slot headers: Content-Type and Location always replace (single-valued per RFC). Cache-Control appends comma-separated (multi-valued per RFC 7234 section 5.2). Validates key per RFC 7230 and strips CRLF from value to prevent header injection.

func (*Ctx) Bind

func (c *Ctx) Bind(v any) error

Bind parses the request body into the given struct.

func (*Ctx) BodyBytes

func (c *Ctx) BodyBytes() ([]byte, error)

BodyBytes returns the raw request body as a safe copy.

func (*Ctx) BodyString

func (c *Ctx) BodyString() string

BodyString returns the request body as a string. Discards body read errors for convenience — use BodyBytes() if you need error handling.

func (*Ctx) Context

func (c *Ctx) Context() context.Context

Context returns the context.Context for this request.

func (*Ctx) Cookie

func (c *Ctx) Cookie(name string) string

Cookie returns the value of the named cookie via the transport interface.

func (*Ctx) File

func (c *Ctx) File(path string) error

File sends a file as the response.

func (*Ctx) Get

func (c *Ctx) Get(key string) any

Get retrieves a value from the request-scoped locals.

func (*Ctx) HTML

func (c *Ctx) HTML(html string) error

HTML sends an HTML response (raw string, no template). For template rendering, use c.Render() with a ViewEngine.

func (*Ctx) Header

func (c *Ctx) Header(name string) string

Header returns a request header value (lazy parsed, cached). Keys are normalized to canonical form so lookups are case-insensitive.

func (*Ctx) IP

func (c *Ctx) IP() string

IP returns the client's IP address.

func (*Ctx) JSON

func (c *Ctx) JSON(v any) error

JSON sends a JSON response using the configured JSON encoder. On the fasthttp path, uses SetBodyRaw for zero-copy response writing: sonic.Marshal allocates a []byte, SetBodyRaw references it (no memcpy), and fasthttp writes it to the TCP socket before GC reclaims it. This eliminates jsonBufPool contention under high concurrency. On net/http or non-default encoder paths, falls back to pooled buffer or direct marshal.

func (*Ctx) Latency

func (c *Ctx) Latency() time.Duration

Latency returns the time elapsed since MarkStart() was called. Returns 0 if MarkStart() was never called (no Logger middleware).

func (*Ctx) Log

func (c *Ctx) Log() *slog.Logger

Log returns a request-scoped logger with pre-set attributes: request_id, method, path. The logger is lazy-initialized on first call and cached for the request lifetime.

func (*Ctx) MarkStart

func (c *Ctx) MarkStart()

MarkStart records the request start time for latency measurement. Called automatically by the Logger middleware. If not called, Latency() returns 0. This avoids the ~30ns cost of time.Now() on every request when timing is not needed.

func (*Ctx) Method

func (c *Ctx) Method() string

Method returns the HTTP method (GET, POST, etc.).

func (*Ctx) Next

func (c *Ctx) Next() error

Next calls the next handler in the middleware chain.

func (*Ctx) NoContent

func (c *Ctx) NoContent() error

NoContent sends a 204 No Content response.

func (*Ctx) Param

func (c *Ctx) Param(name string) string

Param returns a path parameter value by name.

func (*Ctx) ParamInt

func (c *Ctx) ParamInt(name string) (int, error)

ParamInt returns a path parameter parsed as int.

func (*Ctx) Path

func (c *Ctx) Path() string

Path returns the request path.

func (*Ctx) Provide

func (c *Ctx) Provide(key string, value any)

Provide stores a typed value in the request context for later retrieval via Need. This is a semantic alias for Set — it signals intent for dependency injection.

func (*Ctx) Query

func (c *Ctx) Query(name string, def ...string) string

Query returns a query parameter value by name, with optional default. An empty query value (?flag= or ?flag) returns the default.

func (*Ctx) QueryInt

func (c *Ctx) QueryInt(name string, def ...int) int

QueryInt returns a query parameter parsed as int.

func (*Ctx) RawResponseHeader

func (c *Ctx) RawResponseHeader() interface {
	SetBytesV(key string, value []byte)
}

RawResponseHeader provides direct access to the fasthttp response header for zero-overhead header writes. Returns nil if not running on fasthttp. This bypasses all Kruda header abstractions for maximum performance.

func (*Ctx) Redirect

func (c *Ctx) Redirect(url string, code ...int) error

Redirect sends a redirect response. Default status is 302.

func (*Ctx) Render

func (c *Ctx) Render(name string, data any, code ...int) error

Render renders a named template with data using the configured ViewEngine.

app := kruda.New(kruda.WithViews(kruda.NewViewEngine("views/*.html")))
app.Get("/", func(c *kruda.Ctx) error {
    return c.Render("index", Map{"title": "Home"})
})

func (*Ctx) Request

func (c *Ctx) Request() transport.Request

Request returns the underlying transport.Request. Used by contrib modules that need access to the raw request.

func (*Ctx) Responded

func (c *Ctx) Responded() bool

Responded returns whether a response has already been written.

func (*Ctx) ResponseWriter

func (c *Ctx) ResponseWriter() transport.ResponseWriter

ResponseWriter returns the underlying transport.ResponseWriter. Used by contrib modules (e.g. ws) that need direct access to the writer for hijacking.

func (*Ctx) Route

func (c *Ctx) Route() string

Route returns the matched route pattern (e.g. "/users/:id"). Returns the raw path if no pattern was matched (static routes).

func (*Ctx) SSE

func (c *Ctx) SSE(fn func(*SSEStream) error) error

SSE starts a Server-Sent Events stream. Sets appropriate headers and creates an SSEStream for the callback. Returns when the callback returns or the client disconnects.

func (*Ctx) SendBytes

func (c *Ctx) SendBytes(data []byte) error

SendBytes writes the response body and triggers an immediate flush to the transport (eager-send). Unlike SetBody, the data is written before SendBytes returns, so the caller may safely return the buffer to a sync.Pool immediately after the call.

SendBytes is terminal: it returns an error and does not support method chaining. If the response has already been sent (via a prior SendBytes, JSON, Text, etc.), it returns ErrAlreadyResponded.

On the fasthttp serve path the data is written via the embedded fasthttp adapter for zero-copy performance. On net/http and generic transport paths the data is copied by the underlying http.ResponseWriter.

func (*Ctx) SendBytesWithType

func (c *Ctx) SendBytesWithType(contentType string, data []byte) error

SendBytesWithType is an optimized variant of SendBytes that sets Content-Type and writes the body in a single operation. On the fasthttp path this bypasses writeHeadersFastHTTP entirely — no branch checks for cacheControl, location, respHeaders, or cookies. Use this for handlers that only need Content-Type (e.g. json, plaintext, cached-queries).

Precondition: caller must have already set the Date header via SetHeaderBytes.

func (*Ctx) SendBytesWithTypeBytes

func (c *Ctx) SendBytesWithTypeBytes(contentType []byte, data []byte) error

SendBytesWithTypeBytes is the zero-alloc variant of SendBytesWithType. Takes content-type as []byte to avoid string→[]byte conversion on the fasthttp hot path. Use pre-computed []byte content-type constants for maximum performance.

func (*Ctx) SendStaticWithTypeBytes

func (c *Ctx) SendStaticWithTypeBytes(contentType []byte, data []byte) error

SendStaticWithTypeBytes is the zero-copy variant of SendBytesWithTypeBytes for static, pre-allocated response bodies. On the fasthttp path it uses SetBodyRaw instead of SetBody, avoiding a memcopy entirely.

SAFETY: The data slice MUST be immutable for the lifetime of the program (e.g. a package-level var or const-like []byte). Do NOT use with pooled buffers or any data that may be modified after this call returns.

func (*Ctx) Set

func (c *Ctx) Set(key string, value any)

Set stores a value in the request-scoped locals.

func (*Ctx) SetBody

func (c *Ctx) SetBody(data []byte) *Ctx

SetBody sets the response body from a []byte buffer without copying (lazy-send).

The framework flushes the body during post-handler processing — no data is written to the transport until the handler returns. This means the caller MUST keep the buffer valid until the handler returns; do NOT return the buffer to a sync.Pool before the handler completes.

If the handler also calls SendBytes, JSON, or Text, the eager-send wins (responded flag is set) and the SetBody data is silently discarded during the post-handler flush. Calling SetBody multiple times overwrites the previous value (last write wins).

Returns *Ctx for method chaining:

c.SetContentType("application/json").SetBody(buf)

func (*Ctx) SetContentType

func (c *Ctx) SetContentType(ct string) *Ctx

SetContentType sets the Content-Type response header.

Returns *Ctx for method chaining:

c.SetContentType("text/html; charset=utf-8").SetBody(html)

func (*Ctx) SetContext

func (c *Ctx) SetContext(ctx context.Context)

SetContext sets the context.Context for this request.

func (*Ctx) SetCookie

func (c *Ctx) SetCookie(cookie *Cookie) *Ctx

SetCookie sets a cookie on the response. Supports multiple cookies. Cookie values are sanitized to prevent header injection. Supports SameSite attribute and MaxAge<=0 for deletion.

func (*Ctx) SetHeader

func (c *Ctx) SetHeader(key, value string) *Ctx

SetHeader sets a response header, replacing any existing values. Chainable. Common headers (Content-Type, Cache-Control, Location) use fixed slots to avoid map allocation on the hot path. Validates key per RFC 7230 and strips CRLF from value to prevent header injection.

func (*Ctx) SetHeaderBytes

func (c *Ctx) SetHeaderBytes(key string, value []byte) *Ctx

SetHeaderBytes sets a response header with a []byte value. On the fasthttp path this is zero-alloc (avoids []byte→string conversion). Falls back to SetHeader(key, string(value)) on net/http.

func (*Ctx) Status

func (c *Ctx) Status(code int) *Ctx

Status sets the HTTP response status code. Chainable.

func (*Ctx) StatusCode

func (c *Ctx) StatusCode() int

StatusCode returns the current response status code.

func (*Ctx) Stream

func (c *Ctx) Stream(reader io.Reader) error

Stream sends a streaming response from an io.Reader.

func (*Ctx) Text

func (c *Ctx) Text(s string) error

Text sends a plain text response.

func (*Ctx) Transport

func (c *Ctx) Transport() string

Transport returns the transport type string: "nethttp", "fasthttp", or "wing". Contrib modules use this to detect transport-specific behavior (e.g. hijack support).

type ErrorHookFunc

type ErrorHookFunc func(c *Ctx, err error)

ErrorHookFunc is an error lifecycle hook function.

type ErrorMapping

type ErrorMapping struct {
	Status  int
	Message string
}

ErrorMapping maps a Go error to an HTTP status code and message.

type FieldError

type FieldError struct {
	Field   string `json:"field"`   // json tag name or struct field name
	Rule    string `json:"rule"`    // "required", "min", "email", etc.
	Param   string `json:"param"`   // "18" for min=18, "" for required
	Message string `json:"message"` // "email is required"
	Value   string `json:"value"`   // stringified rejected value
}

FieldError represents a single field validation failure.

type FileUpload

type FileUpload struct {
	Name        string
	Size        int64
	ContentType string
	Header      *multipart.FileHeader // raw header for advanced use cases
}

FileUpload represents an uploaded file from a multipart form.

type UploadReq struct {
    Avatar *kruda.FileUpload `form:"avatar" validate:"required,max_size=5mb,mime=image/*"`
}

func (*FileUpload) Open

func (f *FileUpload) Open() (io.ReadCloser, error)

Open opens the uploaded file for reading. The caller must close it when done.

type GoViewEngine

type GoViewEngine struct {
	// contains filtered or unexported fields
}

GoViewEngine wraps html/template as a ViewEngine.

func NewViewEngine

func NewViewEngine(patterns ...string) *GoViewEngine

NewViewEngine creates a ViewEngine from glob patterns.

engine := kruda.NewViewEngine("views/*.html")

func NewViewEngineFS

func NewViewEngineFS(fsys fs.FS, patterns ...string) *GoViewEngine

NewViewEngineFS creates a ViewEngine from an embedded filesystem.

//go:embed views
var viewsFS embed.FS
engine := kruda.NewViewEngineFS(viewsFS, "views/*.html")

func (*GoViewEngine) Render

func (e *GoViewEngine) Render(w io.Writer, name string, data any) error

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group represents a collection of routes that share a common prefix and scoped middleware. Groups can be nested to create hierarchical route structures with inherited middleware chains.

func GroupResource

func GroupResource[T any, ID comparable](g *Group, path string, svc ResourceService[T, ID], opts ...ResourceOption) *Group

GroupResource auto-wires 5 REST endpoints from a ResourceService on a Group. It registers: GET (list), GET/:id (get), POST (create), PUT/:id (update), DELETE/:id (delete).

func (*Group) All

func (g *Group) All(path string, handler HandlerFunc, opts ...RouteOption) *Group

All registers a route on all standard HTTP methods on this group.

func (*Group) Delete

func (g *Group) Delete(path string, handler HandlerFunc, opts ...RouteOption) *Group

Delete registers a DELETE route on this group.

func (*Group) Done

func (g *Group) Done() *App

Done returns the parent App for method chaining back to the root.

app.Group("/api").
    Use(authMiddleware).
    Get("/users", listUsers).
    Done().
    Get("/health", healthCheck)

func (*Group) Get

func (g *Group) Get(path string, handler HandlerFunc, opts ...RouteOption) *Group

Get registers a GET route on this group.

func (*Group) Group

func (g *Group) Group(prefix string) *Group

Group creates a nested group with the combined prefix of parent and child.

v1 := api.Group("/v1")
v1.Get("/users", listUsers) // matches /api/v1/users

func (*Group) Guard

func (g *Group) Guard(middleware ...HandlerFunc) *Group

Guard is a semantic alias for Use. It reads as "protect these routes with" and is intended for auth/permission middleware.

admin := api.Group("/admin").Guard(authMiddleware)

func (*Group) Head

func (g *Group) Head(path string, handler HandlerFunc, opts ...RouteOption) *Group

Head registers a HEAD route on this group.

func (*Group) Options

func (g *Group) Options(path string, handler HandlerFunc, opts ...RouteOption) *Group

Options registers an OPTIONS route on this group.

func (*Group) Patch

func (g *Group) Patch(path string, handler HandlerFunc, opts ...RouteOption) *Group

Patch registers a PATCH route on this group.

func (*Group) Post

func (g *Group) Post(path string, handler HandlerFunc, opts ...RouteOption) *Group

Post registers a POST route on this group.

func (*Group) Put

func (g *Group) Put(path string, handler HandlerFunc, opts ...RouteOption) *Group

Put registers a PUT route on this group.

func (*Group) Use

func (g *Group) Use(middleware ...HandlerFunc) *Group

Use adds scoped middleware to this group. The middleware applies only to routes registered within this group and its nested groups. Returns the group for method chaining.

type HandlerFunc

type HandlerFunc func(c *Ctx) error

HandlerFunc is the function signature for route handlers and middleware.

func HealthHandler

func HealthHandler(opts ...HealthOption) HandlerFunc

HealthHandler returns a HandlerFunc that discovers all HealthChecker implementations from the DI container and runs them in parallel.

type HealthChecker

type HealthChecker interface {
	Check(ctx context.Context) error
}

HealthChecker is implemented by services that can report their health status. Implementations MUST respect ctx.Done() to avoid goroutine leaks on timeout.

type HealthOption

type HealthOption func(*healthConfig)

HealthOption configures the health check handler.

func WithHealthTimeout

func WithHealthTimeout(d time.Duration) HealthOption

WithHealthTimeout sets the timeout for health checks.

type HookFunc

type HookFunc func(c *Ctx) error

HookFunc is a lifecycle hook function.

type Hooks

type Hooks struct {
	OnRequest    []HookFunc
	OnResponse   []HookFunc
	BeforeHandle []HookFunc
	AfterHandle  []HookFunc
	OnError      []ErrorHookFunc
	OnShutdown   []func()
	OnParse      []func(c *Ctx, input any) error
}

Hooks holds all lifecycle hook slices.

Full lifecycle order (see spec §10.2):

OnRequest → OnParse → Middleware → BeforeHandle → Handler → AfterHandle → OnResponse → OnError

BeforeHandle fires after middleware but before the final handler. AfterHandle fires after the handler returns (before OnResponse). All hooks are zero-cost when not registered — ServeFast checks a single bool flag.

type Initializer

type Initializer interface {
	OnInit(ctx context.Context) error
}

Initializer is implemented by services that need startup initialization. Services implementing this interface will have OnInit called during container.Start() in registration order.

type KrudaError

type KrudaError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Detail  string `json:"detail,omitempty"`
	Err     error  `json:"-"`
	// contains filtered or unexported fields
}

KrudaError is the standard error type for Kruda. It carries an HTTP status code and is auto-serialized as JSON.

func BadRequest

func BadRequest(message string) *KrudaError

BadRequest returns a 400 error.

func Conflict

func Conflict(message string) *KrudaError

Conflict returns a 409 error.

func Forbidden

func Forbidden(message string) *KrudaError

Forbidden returns a 403 error.

func InternalError

func InternalError(message string) *KrudaError

InternalError returns a 500 error.

func NewError

func NewError(code int, message string, err ...error) *KrudaError

NewError creates a new KrudaError with optional wrapped error.

func NotFound

func NotFound(message string) *KrudaError

NotFound returns a 404 error.

func TooManyRequests

func TooManyRequests(message string) *KrudaError

TooManyRequests returns a 429 error.

func Unauthorized

func Unauthorized(message string) *KrudaError

Unauthorized returns a 401 error.

func UnprocessableEntity

func UnprocessableEntity(message string) *KrudaError

UnprocessableEntity returns a 422 error.

func (*KrudaError) Error

func (e *KrudaError) Error() string

Error implements the error interface.

func (*KrudaError) Unwrap

func (e *KrudaError) Unwrap() error

Unwrap returns the wrapped error for errors.Is/As support.

type Map

type Map = map[string]any

Map is a convenience type alias for map[string]any. Use it for quick JSON responses without defining a struct.

c.JSON(kruda.Map{"message": "hello", "ok": true})

type MiddlewareFunc

type MiddlewareFunc = HandlerFunc

MiddlewareFunc is a type alias for HandlerFunc for semantic clarity. Using a type alias (=) means MiddlewareFunc and HandlerFunc are interchangeable.

type Module

type Module interface {
	Install(c *Container) error
}

Module is the interface for modular DI registration. Modules group related service registrations into reusable units.

type Option

type Option func(*App)

Option is a functional option for configuring the App.

func FastHTTP

func FastHTTP() Option

FastHTTP selects the fasthttp transport. Use when you need fasthttp's battle-tested HTTP/1.1 handling.

func NetHTTP

func NetHTTP() Option

NetHTTP selects the net/http transport for HTTP/2, TLS, and Windows compatibility. Use this when you need HTTP/2 auto-negotiation, TLS, or are running on Windows.

func Wing

func Wing() Option

Wing selects the Wing transport (epoll+eventfd, Linux only). This is the default on Linux — calling Wing() is optional but explicit. On non-Linux platforms, falls back to fasthttp.

func WithBodyLimit

func WithBodyLimit(limit int) Option

WithBodyLimit sets the maximum request body size.

func WithContainer

func WithContainer(c *Container) Option

WithContainer attaches a DI container to the App. The container is optional — apps without it work identically to Phase 1-3. When configured, the container is accessible to handlers via Resolve[T]() and is automatically shut down when the App shuts down.

func WithDevMode

func WithDevMode(enabled bool) Option

WithDevMode enables or disables development mode. When enabled, the framework relaxes X-Frame-Options to SAMEORIGIN and activates the dev error page (when implemented). Default: false (production mode). Also auto-detected via KRUDA_ENV=development.

func WithEnvPrefix

func WithEnvPrefix(prefix string) Option

WithEnvPrefix reads config from environment variables with the given prefix. Maps CamelCase field names to SCREAMING_SNAKE_CASE env vars. Example: prefix="APP" reads APP_READ_TIMEOUT, APP_BODY_LIMIT, etc. Missing or unparseable env vars are silently ignored (defaults are kept).

func WithErrorHandler

func WithErrorHandler(h func(c *Ctx, err *KrudaError)) Option

WithErrorHandler sets a custom error handler.

func WithHTTP3

func WithHTTP3(certFile, keyFile string) Option

WithHTTP3 enables HTTP/3 dual-stack serving (QUIC on UDP + HTTP/2 on TCP). Requires TLS certificate and key since QUIC mandates TLS 1.3. When enabled, the Alt-Svc header is auto-injected to advertise HTTP/3.

func WithIdleTimeout

func WithIdleTimeout(d time.Duration) Option

WithIdleTimeout sets the idle timeout.

func WithJSONDecoder

func WithJSONDecoder(dec func(data []byte, v any) error) Option

WithJSONDecoder sets a custom JSON decoder.

func WithJSONEncoder

func WithJSONEncoder(enc func(v any) ([]byte, error)) Option

WithJSONEncoder sets a custom JSON encoder. This disables the default streaming buffer pool optimization. To re-enable pooling with a custom encoder, also call WithJSONStreamEncoder.

func WithJSONStreamEncoder

func WithJSONStreamEncoder(enc func(buf *bytes.Buffer, v any) error) Option

WithJSONStreamEncoder sets a streaming JSON encoder that writes into a provided bytes.Buffer. When set, c.JSON() uses a sync.Pool'd buffer with this encoder instead of JSONEncoder, avoiding one allocation per response.

func WithLegacySecurityHeaders

func WithLegacySecurityHeaders() Option

WithLegacySecurityHeaders restores Phase 1-4 security header defaults for backward compatibility. Sets:

  • X-XSS-Protection: "1; mode=block"
  • X-Frame-Options: "SAMEORIGIN"
  • Referrer-Policy: "no-referrer"
  • X-Content-Type-Options: "nosniff" (unchanged)

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets a custom logger.

func WithMaxBodySize

func WithMaxBodySize(size int) Option

WithMaxBodySize sets the maximum request body size in bytes. Alias for WithBodyLimit. When a request body exceeds this limit, the framework responds with HTTP 413.

func WithOpenAPIInfo

func WithOpenAPIInfo(title, version, description string) Option

WithOpenAPIInfo enables OpenAPI spec generation with the given metadata. When configured, a GET handler is auto-registered at the OpenAPI path (default: /openapi.json).

func WithOpenAPIPath

func WithOpenAPIPath(path string) Option

WithOpenAPIPath sets the path where the OpenAPI spec is served.

func WithOpenAPITag

func WithOpenAPITag(name, description string) Option

WithOpenAPITag adds a tag definition to the OpenAPI spec.

func WithPathTraversal

func WithPathTraversal() Option

WithPathTraversal enables path traversal prevention. Requests with path traversal patterns (../, encoded dots) are rejected.

func WithReadTimeout

func WithReadTimeout(d time.Duration) Option

WithReadTimeout sets the read timeout.

func WithSecureHeaders

func WithSecureHeaders() Option

WithSecureHeaders enables default security headers on all responses. Headers include X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, and Referrer-Policy.

func WithSecurity

func WithSecurity() Option

WithSecurity enables all security features: security headers and path traversal prevention. Equivalent to using both WithSecureHeaders() and WithPathTraversal(). Recommended for production deployments.

func WithShutdownTimeout

func WithShutdownTimeout(d time.Duration) Option

WithShutdownTimeout sets the graceful shutdown timeout.

func WithTLS

func WithTLS(certFile, keyFile string) Option

WithTLS configures TLS for HTTPS and HTTP/2 auto-negotiation.

func WithTransport

func WithTransport(t transport.Transport) Option

WithTransport sets a custom transport.

func WithTrustProxy

func WithTrustProxy(trust bool) Option

WithTrustProxy enables trusting proxy headers (X-Forwarded-For, X-Real-IP). Default is false — only the direct connection's remote address is used.

func WithValidator

func WithValidator(v *Validator) Option

WithValidator sets a pre-configured Validator on the App.

func WithViews

func WithViews(engine ViewEngine) Option

WithViews sets the template engine for c.Render().

func WithWriteTimeout

func WithWriteTimeout(d time.Duration) Option

WithWriteTimeout sets the write timeout.

type ResourceOption

type ResourceOption func(*resourceConfig)

ResourceOption configures auto-wired CRUD endpoints.

func WithResourceExcept

func WithResourceExcept(methods ...string) ResourceOption

WithResourceExcept excludes specific CRUD methods from registration. Pass HTTP method names like "GET", "POST", "PUT", "DELETE".

func WithResourceIDParam

func WithResourceIDParam(param string) ResourceOption

WithResourceIDParam overrides the default "id" path parameter name.

func WithResourceMiddleware

func WithResourceMiddleware(mw ...HandlerFunc) ResourceOption

WithResourceMiddleware adds middleware that applies only to the auto-wired CRUD endpoints.

func WithResourceOnly

func WithResourceOnly(methods ...string) ResourceOption

WithResourceOnly restricts which CRUD methods are registered. Pass HTTP method names like "GET", "POST", "PUT", "DELETE". Note: "GET" registers both list (GET /path) and get-by-id (GET /path/:id). Use "LIST" for list-only or "GET_BY_ID" for get-by-id-only.

type ResourceService

type ResourceService[T any, ID comparable] interface {
	List(ctx context.Context, page int, limit int) ([]T, int, error)
	Create(ctx context.Context, item T) (T, error)
	Get(ctx context.Context, id ID) (T, error)
	Update(ctx context.Context, id ID, item T) (T, error)
	Delete(ctx context.Context, id ID) error
}

ResourceService is the generic interface for auto-wired CRUD endpoints. Implement this interface to get 5 REST endpoints (List, Create, Get, Update, Delete) automatically registered via the Resource() or GroupResource() functions.

type RouteOption

type RouteOption func(*routeConfig)

RouteOption configures per-route metadata (for future OpenAPI integration).

func WingJSON

func WingJSON() RouteOption

WingJSON — JSON response, no external I/O. Inline in ioLoop.

func WingPlaintext

func WingPlaintext() RouteOption

WingPlaintext — static text, health checks. Inline in ioLoop.

func WingQuery

func WingQuery() RouteOption

WingQuery — DB/Redis short I/O. Blocking goroutine per connection.

func WingRender

func WingRender() RouteOption

WingRender — DB + template/HTML rendering. Blocking goroutine per connection.

func WithDescription

func WithDescription(desc string) RouteOption

WithDescription sets a route description (used by OpenAPI in Phase 2B).

func WithTags

func WithTags(tags ...string) RouteOption

WithTags sets route tags (used by OpenAPI in Phase 2B).

type RouteParam

type RouteParam struct {
	Key   string
	Value string
}

RouteParam is a key-value pair for a single path parameter.

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router is a radix tree router with a separate tree per HTTP method. It provides O(1) child lookup via the indices string on each node.

func (*Router) Compile

func (r *Router) Compile()

Compile freezes the router tree and performs AOT optimizations: sorts children by frequency, flattens single-child static chains, builds a static route map for O(1) exact-match lookup, and caches allowed methods for static paths.

type SSEStream

type SSEStream struct {
	// contains filtered or unexported fields
}

SSEStream writes Server-Sent Events to the client.

func (*SSEStream) Comment

func (s *SSEStream) Comment(text string) error

Comment sends an SSE comment (keep-alive).

func (*SSEStream) Data

func (s *SSEStream) Data(data any) error

Data sends an unnamed event with data (JSON-encoded).

func (*SSEStream) Done

func (s *SSEStream) Done() <-chan struct{}

Done returns a channel that closes when the client disconnects.

func (*SSEStream) Event

func (s *SSEStream) Event(event string, data any) error

Event sends a named event with data (JSON-encoded).

func (*SSEStream) EventWithID

func (s *SSEStream) EventWithID(id, event string, data any) error

EventWithID sends a named event with an ID (for client reconnection).

func (*SSEStream) Retry

func (s *SSEStream) Retry(ms int) error

Retry sends a retry directive (reconnect interval in ms).

type SecurityConfig

type SecurityConfig struct {
	// Security header values (applied when WithSecureHeaders() or WithSecurity() is used)
	XSSProtection         string // default: "0" (disabled per modern best practice)
	ContentTypeNosniff    string // default: "nosniff"
	XFrameOptions         string // default: "DENY"
	HSTSMaxAge            int    // default: 0 (disabled), recommended: 31536000
	ContentSecurityPolicy string // default: ""
	ReferrerPolicy        string // default: "strict-origin-when-cross-origin"
}

SecurityConfig controls security headers and behavior.

type Shutdowner

type Shutdowner interface {
	OnShutdown(ctx context.Context) error
}

Shutdowner is implemented by services that need cleanup on shutdown. Services implementing this interface will have OnShutdown called during container.Shutdown() in reverse registration order.

type StaticOption

type StaticOption func(*staticConfig)

StaticOption configures static file serving.

func WithBrowse

func WithBrowse() StaticOption

WithBrowse enables directory listing.

func WithIndex

func WithIndex(name string) StaticOption

WithIndex sets the index file name (default: "index.html").

func WithMaxAge

func WithMaxAge(seconds int) StaticOption

WithMaxAge sets Cache-Control max-age in seconds.

func WithSPA

func WithSPA() StaticOption

WithSPA serves index.html for any path that doesn't match a file.

type TestClient

type TestClient struct {
	// contains filtered or unexported fields
}

TestClient provides a fluent API for testing Kruda applications without starting a real HTTP server. It is safe for concurrent use.

func NewTestClient

func NewTestClient(app *App) *TestClient

NewTestClient creates a new test client for the given app.

func (*TestClient) Delete

func (tc *TestClient) Delete(path string) (*TestResponse, error)

Delete sends a DELETE request to the given path.

func (*TestClient) Get

func (tc *TestClient) Get(path string) (*TestResponse, error)

Get sends a GET request to the given path.

func (*TestClient) Head

func (tc *TestClient) Head(path string) (*TestResponse, error)

Head sends a HEAD request to the given path.

func (*TestClient) Options

func (tc *TestClient) Options(path string) (*TestResponse, error)

Options sends an OPTIONS request to the given path.

func (*TestClient) Patch

func (tc *TestClient) Patch(path string, body any) (*TestResponse, error)

Patch sends a PATCH request to the given path with the given body.

func (*TestClient) Post

func (tc *TestClient) Post(path string, body any) (*TestResponse, error)

Post sends a POST request to the given path with the given body.

func (*TestClient) Put

func (tc *TestClient) Put(path string, body any) (*TestResponse, error)

Put sends a PUT request to the given path with the given body.

func (*TestClient) Request

func (tc *TestClient) Request(method, path string) *TestRequest

Request creates a new TestRequest builder for the given method and path.

func (*TestClient) WithCookie

func (tc *TestClient) WithCookie(name, value string) *TestClient

WithCookie sets a default cookie for all requests from this client.

func (*TestClient) WithHeader

func (tc *TestClient) WithHeader(key, value string) *TestClient

WithHeader sets a default header for all requests from this client.

type TestRequest

type TestRequest struct {
	// contains filtered or unexported fields
}

TestRequest is a builder for constructing test HTTP requests.

func (*TestRequest) Body

func (tr *TestRequest) Body(body any) *TestRequest

Body sets the request body.

func (*TestRequest) ContentType

func (tr *TestRequest) ContentType(ct string) *TestRequest

ContentType sets the Content-Type header for the request.

func (*TestRequest) Cookie

func (tr *TestRequest) Cookie(name, value string) *TestRequest

Cookie sets a request-level cookie.

func (*TestRequest) Header

func (tr *TestRequest) Header(key, value string) *TestRequest

Header sets a request-level header.

func (*TestRequest) Query

func (tr *TestRequest) Query(key, value string) *TestRequest

Query sets a query parameter.

func (*TestRequest) Send

func (tr *TestRequest) Send() (*TestResponse, error)

Send executes the test request and returns the response.

type TestResponse

type TestResponse struct {
	// contains filtered or unexported fields
}

TestResponse wraps an httptest.ResponseRecorder for easy assertions.

func (*TestResponse) Body

func (tr *TestResponse) Body() []byte

Body returns the response body as bytes.

func (*TestResponse) BodyString

func (tr *TestResponse) BodyString() string

BodyString returns the response body as a string.

func (*TestResponse) Header

func (tr *TestResponse) Header(key string) string

Header returns the value of the given response header.

func (*TestResponse) JSON

func (tr *TestResponse) JSON(v any) error

JSON unmarshals the response body into the given value.

func (*TestResponse) StatusCode

func (tr *TestResponse) StatusCode() int

StatusCode returns the HTTP status code of the response.

type ValidationError

type ValidationError struct {
	Errors []FieldError `json:"errors"`
}

ValidationError holds structured validation errors. Implements error and json.Marshaler.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error implements the error interface.

func (*ValidationError) MarshalJSON

func (e *ValidationError) MarshalJSON() ([]byte, error)

MarshalJSON produces the structured JSON response. Uses the build-tag-selected JSON engine (sonic when available, else encoding/json).

type Validator

type Validator struct {
	// contains filtered or unexported fields
}

Validator holds registered rules and message templates. Created once per App, configured at startup.

func NewValidator

func NewValidator() *Validator

NewValidator creates a Validator with built-in rules and default messages.

func (*Validator) Messages

func (v *Validator) Messages(overrides map[string]string) *Validator

Messages overrides default message templates. Chainable.

func (*Validator) Register

func (v *Validator) Register(name string, fn ValidatorFunc) *Validator

Register adds a custom validation rule. Chainable.

type ValidatorFunc

type ValidatorFunc func(value any, param string) bool

ValidatorFunc is the signature for validation rule functions. value is the field value to validate, param is the rule parameter (e.g. "18" for min=18, "" for required). Returns true if valid, false if invalid.

type ViewEngine

type ViewEngine interface {
	Render(w io.Writer, name string, data any) error
}

ViewEngine renders named templates with data.

Directories

Path Synopsis
cmd
kruda module
contrib
jwt module
prometheus module
ratelimit module
ws module
examples
auth command
Example: Auth — JWT-like Authentication with HMAC-SHA256
Example: Auth — JWT-like Authentication with HMAC-SHA256
auto-crud command
Example: Auto CRUD — ResourceService with app.Resource()
Example: Auto CRUD — ResourceService with app.Resource()
clean-arch command
Clean Architecture — domain core has zero external imports.
Clean Architecture — domain core has zero external imports.
crud command
Example: Phase 4 Ecosystem — DI, Modules, Resource, Health
Example: Phase 4 Ecosystem — DI, Modules, Resource, Health
database command
Example: Database — Repository Pattern with In-Memory Store
Example: Database — Repository Pattern with In-Memory Store
di-services command
Example: DI Container with Services and Modules
Example: DI Container with Services and Modules
error-handling command
Example: Error Handling — Error Mapping, KrudaError, Custom Error Handlers
Example: Error Handling — Error Mapping, KrudaError, Custom Error Handlers
flat command
Flat pattern — everything in one file.
Flat pattern — everything in one file.
health-checks command
Example: Health Checks — HealthChecker Services and HealthHandler
Example: Health Checks — HealthChecker Services and HealthHandler
hello command
hexagonal command
Hexagonal Architecture (Ports & Adapters).
Hexagonal Architecture (Ports & Adapters).
json-api command
Example: JSON API with Typed Handlers
Example: JSON API with Typed Handlers
layered command
Layered pattern — handler → service → repository.
Layered pattern — handler → service → repository.
middleware command
Example: Middleware — Built-in and Custom Middleware
Example: Middleware — Built-in and Custom Middleware
openapi command
Example: Auto-Generated OpenAPI 3.1 Spec
Example: Auto-Generated OpenAPI 3.1 Spec
sse command
static-files command
testing command
Example: Testing — TestClient Usage Patterns
Example: Testing — TestClient Usage Patterns
typed-handlers command
Example: Typed Handlers with C[T]
Example: Typed Handlers with C[T]
internal
Package json provides a pluggable JSON engine for Kruda.
Package json provides a pluggable JSON engine for Kruda.
wing module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL