Architecture
Understanding rocco's internal architecture helps you make better design decisions and debug issues effectively.
Request Flow
When a request arrives, it flows through several stages:
Request
│
▼
┌──────────────────────────────────────────────────────────┐
│ stdlib ServeMux │
│ ┌─────────────┐ │
│ │ Route │ Match path and method to handler │
│ │ Matching │ │
│ └──────┬──────┘ │
└─────────│────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Middleware Chain │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Engine │→ │ Handler │→ │ Auth │ │
│ │ Middleware │ │ Middleware │ │ Middleware │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────┬────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Handler Adapter │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Extract │→ │ Parse │→ │ Validate │ │
│ │ Params │ │ Body │ │ Input │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Execute │ Call handler function │
│ │ Handler │ │
│ └──────┬──────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Success Path │ │ Error Path │ │
│ │ Marshal output │ │ Map to response │ │
│ │ Write response │ │ Write error │ │
│ └─────────────────┘ └─────────────────┘ │
└──────────────────────────────────────────────────────────┘
│
▼
Response
Component Overview
Stdlib Router
Rocco is built on Go 1.22+ stdlib http.ServeMux with native path parameter support. The router handles:
- URL routing with path parameters (
/users/{id}) - HTTP method routing (
GET /users/{id}) - Context propagation
Access the ServeMux directly for advanced use cases:
engine.Router().HandleFunc("GET /custom", customHandler)
Engine
The Engine orchestrates the server lifecycle:
type Engine struct {
config *EngineConfig
server *http.Server
mux *http.ServeMux
globalMiddleware []func(http.Handler) http.Handler
handlers []Endpoint
extractIdentity func(context.Context, *http.Request) (Identity, error)
spec *EngineSpec
}
Key responsibilities:
- Configure HTTP server timeouts
- Manage global middleware
- Register handlers with the router
- Build authentication/authorization middleware
- Generate OpenAPI specifications
- Handle graceful shutdown
Handler Adapter
The handler adapter bridges typed handlers to stdlib's http.Handler interface:
func (e *Engine) adaptHandler(handler Endpoint) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Emit request received event
// Call handler.Process()
// Emit completion/failure event
}
}
Handler Processing
The Handler.Process() method executes the request lifecycle:
- Extract Parameters - Read path/query params from request
- Read Body - Read request body with size limits
- Parse JSON - Unmarshal body into typed struct
- Validate Input - Run struct validation
- Execute Handler - Call user function
- Handle Errors - Map errors to responses
- Validate Output - Optional output validation
- Write Response - Marshal and write JSON
Middleware Execution
Middleware executes in a specific order:
Request → Engine MW 1 → Engine MW 2 → Handler MW → Auth MW → Handler
Response ← Engine MW 1 ← Engine MW 2 ← Handler MW ← Auth MW ← Handler
Engine Middleware
Applied to all requests:
engine.WithMiddleware(middleware.Logger)
engine.WithMiddleware(middleware.Recoverer)
Handler Middleware
Applied to specific handlers:
handler.WithMiddleware(rateLimiter)
Auth Middleware
Automatically added when handler requires authentication:
handler.WithAuthentication() // Adds auth middleware
handler.WithScopes("read") // Adds auth + authz middleware
handler.WithRoles("admin") // Adds auth + authz middleware
Error Handling Flow
Handler returns error
│
▼
┌────────────┐
│ Is rocco │──No──→ Log error, return 500
│ Error? │
└─────┬──────┘
│Yes
▼
┌────────────┐
│ Is error │──No──→ Log warning, return 500
│ declared? │ (undeclared sentinel)
└─────┬──────┘
│Yes
▼
Return structured
error response
Undeclared sentinel errors indicate a programming error - the handler returned an error it didn't declare. This is logged as a warning and returns 500 to avoid leaking internal details.
Event Emission
Rocco emits events throughout the request lifecycle via capitan:
| Stage | Events |
|---|---|
| Server lifecycle | EngineCreated, EngineStarting, EngineShutdownStarted, EngineShutdownComplete |
| Handler registration | HandlerRegistered |
| Request start | RequestReceived |
| Handler execution | HandlerExecuting, HandlerSuccess, HandlerError, HandlerSentinelError |
| Request end | RequestCompleted, RequestFailed |
| Errors | RequestParamsInvalid, RequestBodyParseError, RequestValidationInputFailed |
OpenAPI Generation
OpenAPI specs are generated from handler metadata:
Handler Registration
│
▼
┌───────────────────────────────────────┐
│ Metadata Collection │
│ - Input/Output type metadata │
│ - Path/Query parameters │
│ - Error definitions │
│ - Tags, summary, description │
└───────────────────┬───────────────────┘
│
▼
┌───────────────────────────────────────┐
│ Schema Generation │
│ - Struct → JSON Schema │
│ - Validation tags → constraints │
│ - Error details → schemas │
└───────────────────┬───────────────────┘
│
▼
┌───────────────────────────────────────┐
│ Spec Assembly │
│ - Paths from handlers │
│ - Components from types │
│ - Info from EngineSpec │
└───────────────────────────────────────┘
Type metadata is extracted using sentinel, which scans struct types at handler creation time.
Threading Model
Handler Registration: All handlers must be registered before calling Start(). Registration is not thread-safe.
Request Handling: Each request is handled in its own goroutine. Handlers may run concurrently.
Shutdown: Graceful shutdown waits for active requests to complete within the context deadline.
Memory and Performance
- Handler creation: Type metadata is scanned once at handler creation
- OpenAPI spec: Generated once on first request, cached thereafter
- Body parsing: Uses
io.ReadAllwith configurable size limits - Validation: Validator instance created per handler (thread-safe)
Next Steps
- Handler Guide - Advanced handler patterns
- Best Practices - Production recommendations
See Also
- Observability Cookbook - Event handling patterns
- Events Reference - Complete event list