Context
The *zen.Ctx is created per-request via sync.Pool and carries the request, response writer,
and a key-value store through the middleware chain. It's the primary interface handlers interact with.
Retrieval
Inside a handler registered via r.GET(), the context is passed directly. Outside handlers
(e.g., in an http.Handler), use FromRequest or FromContext:
// Inside a handler (registered via r.GET, r.Use, etc.)
func handler(c *zen.Ctx) {
// c is directly available
}
// From an http.Handler (e.g., raw stdlib handlers)
ctx, ok := zen.FromRequest(r)
// Or from context.Context
ctx, ok := zen.FromContext(r.Context())
Both return (*Ctx, bool) - the bool is false if no zen Ctx is in the chain.
Fields
| Field | Type | Description |
|---|---|---|
c.Response | http.ResponseWriter | The response writer |
c.Request | *http.Request | The incoming request |
These are the raw net/http objects, giving you full access to the standard library
without abstraction leaks.
Key-Value Store
Use Set/Get to pass data between middleware and handlers (e.g., authenticated user,
request ID):
// Store (typically in middleware)
c.Set("user", &user)
c.Set("request_id", "abc-123")
// Retrieve (in handler or later middleware)
val, ok := c.Get("user")
if ok {
user := val.(*User)
}
The store is thread-safe (backed by sync.RWMutex) and lazily initialized - no
overhead if you never call Set.
Lifecycle
Engine.ServeHTTPretrieves a Ctx fromsync.Pool- It's stored in the request context via
context.WithValueforFromRequestaccess - The Context passes through the middleware chain and into the handler
- After the handler returns, the Ctx is returned to the pool for reuse
The Context is not safe to use after the handler returns. If you need data from the context in a goroutine, copy the values out before spawning the goroutine.