Skip to main content

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

FieldTypeDescription
c.Responsehttp.ResponseWriterThe response writer
c.Request*http.RequestThe 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

  1. Engine.ServeHTTP retrieves a Ctx from sync.Pool
  2. It's stored in the request context via context.WithValue for FromRequest access
  3. The Context passes through the middleware chain and into the handler
  4. 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.