Docs Context

Context

Context is the only object that flows through the entire request lifecycle in Plumego.

It is not a service locator.
It is not a dependency container.
It is not a place to hide business logic.

Plumego’s Context is intentionally minimal, predictable, and request-scoped.

Understanding what it is — and what it is not — is essential to using the framework correctly.


What the Context Represents

A Plumego Context represents one HTTP request.

It exists to:

  • Carry request data
  • Carry response writers
  • Carry request-scoped metadata
  • Flow through middleware and handlers

Nothing more.

If a value does not conceptually belong to this request,
it does not belong in the Context.


Context Lifetime

The Context lifecycle is strictly bounded:

Request Received
→ Context Created
→ Middleware Chain
→ Handler
→ Response Written
→ Context Discarded

Key properties:

  • One Context per request
  • Never shared across requests
  • Never reused
  • Never global

This guarantee makes concurrency predictable.


What the Core Context Provides

At a minimum, the Plumego Context provides access to:

  • The incoming HTTP request
  • The response writer
  • Request-scoped storage
  • Convenience helpers for responses

Conceptually:

type Context struct {
	Request        *http.Request
	ResponseWriter http.ResponseWriter
	// request-scoped storage
}

Exact APIs may evolve, but the guarantees do not.


Request-Scoped Storage

Context provides a small key–value store for request-scoped metadata.

Typical uses include:

  • Trace IDs
  • Request IDs
  • Authenticated identity
  • Deadlines or flags
  • Middleware annotations

Example (conceptual):

ctx.Set("trace_id", traceID)
id, _ := ctx.Get("trace_id")

Rules:

  • Values must be request-scoped
  • Keys should be unique and well-defined
  • Stored values should be immutable after set

Context storage is not a general cache.


Context and Middleware Flow

The Context is passed by reference through the middleware chain.

Each middleware:

  • Receives the same Context instance
  • May read from it
  • May add metadata to it
  • Must not replace it

This ensures:

  • Consistent state visibility
  • Predictable execution order
  • No hidden forks or branches

Context and Handlers

Handlers receive the Context as their only framework-level input.

This enforces a clear boundary:

  • Handlers adapt Context → usecase input
  • Usecases do not depend on Context
  • Domain logic never sees Context

If Context reaches your domain, boundaries are already broken.


Context Is Not a Dependency Container

A common temptation is to treat Context as a place to fetch services:

db := ctx.Get("db")

This is explicitly discouraged.

Why:

  • It hides dependencies
  • It breaks testability
  • It creates implicit coupling
  • It turns Context into a service locator

Dependencies should be injected explicitly, not pulled from Context.


Context Is Not Business State

Do not store business entities or workflow state in Context.

Bad examples:

  • Orders
  • Domain aggregates
  • Mutable business flags

Context is about request metadata, not business data.


Context and Cancellation

Plumego Context is aligned with Go’s context.Context.

Cancellation and deadlines propagate naturally:

  • Client disconnect
  • Server shutdown
  • Timeout middleware

Long-running operations should respect cancellation signals.

Ignoring cancellation is a correctness bug, not an optimization issue.


Context Mutation Discipline

Mutation rules are simple:

  • Middleware may add metadata
  • Handlers may read metadata
  • No one should remove or overwrite meaningfully owned keys

If multiple components fight over the same keys,
naming and ownership are unclear.


Context Keys: Naming and Ownership

Good practice:

  • Use well-defined key names
  • Prefer constants
  • Document ownership

Example:

const ContextKeyTraceID = "trace_id"

Avoid ad-hoc string keys scattered across the codebase.


Context and Testing

Because Context is explicit and request-scoped:

  • Middleware can be tested with a fake Context
  • Handlers can be tested with constructed requests
  • Usecases remain independent of Context entirely

If Context is required to test core logic,
architecture boundaries have been crossed.


Common Anti-Patterns

Using Context as Global State

This defeats request isolation and leads to race conditions.


Passing Context into Usecases

This couples application logic to the framework.


Storing Mutable Shared Objects

Context values should be treated as immutable metadata.


Why Plumego Keeps Context Small

Every additional responsibility added to Context:

  • Increases coupling
  • Encourages misuse
  • Makes reasoning harder

Plumego deliberately keeps Context minimal so that:

Most architectural decisions remain in your code, not in the framework.


Summary

In Plumego:

  • Context is request-scoped
  • Context carries metadata, not logic
  • Context flows through middleware and handlers
  • Context never enters the domain
  • Context is explicit and predictable

Treat Context as a carrier, not a container.


Next

With Context understood, continue with:

→ Router

This explains how Plumego matches requests and dispatches handlers — without magic.