Docs Middleware

Middleware

Middleware is the mechanism Plumego uses to handle cross-cutting concerns.

Examples include:

  • Logging
  • Authentication
  • Authorization
  • Tracing
  • Panic recovery
  • Rate limiting

Middleware sits between routing and handler execution, and operates on the same request-scoped Context.

Understanding middleware is essential for building correct and maintainable Plumego applications.


Where Middleware Fits in the Lifecycle

Middleware executes after routing and before the handler.

The simplified lifecycle is:

Request
→ Router
→ Middleware Chain
→ Handler
← Middleware Chain
← Response

Middleware wraps the handler and can execute logic:

  • Before the handler
  • After the handler
  • Instead of the handler (by short-circuiting)

Middleware Execution Order

Middleware execution order is explicit and deterministic.

Given two middleware functions, A and B, registered in this order:

app.Use(A)
app.Use(B)

The execution order is:

Request →
  A →
    B →
      Handler →
    B →
  A →
Response

Key properties:

  • Order is defined by registration order
  • There is no reordering or prioritization
  • Understanding order requires reading the registration code — nothing else

This predictability is intentional.


The Middleware Contract

Conceptually, a Plumego middleware:

  • Receives a *plumego.Context
  • Decides whether to continue the chain
  • Optionally performs work before and after the next step

Although the exact function signature is defined elsewhere, the conceptual contract is:

func(ctx *Context, next NextFunc)

The middleware must explicitly call next() to continue request processing.

If next() is not called, the request stops there.


Short-Circuiting Requests

Middleware may decide to stop request processing early.

Common examples:

  • Authentication failure
  • Authorization denial
  • Rate limit exceeded

In these cases, middleware typically:

  1. Writes a response
  2. Returns without calling next()

Once the response is written, the handler will not run.

This behavior is explicit and visible in the middleware code.


Middleware and Context Mutation

Middleware commonly enriches the context with request-scoped data:

  • User identity
  • Permissions
  • Trace identifiers
  • Request metadata

Guidelines:

  • Set values early in the chain
  • Use immutable or simple data
  • Avoid overwriting existing values unless intentional

All middleware and the handler share the same Context instance.


Middleware Responsibilities

Middleware is appropriate for concerns that are:

  • Orthogonal to business logic
  • Shared across multiple routes
  • Independent of specific domain rules

Good middleware responsibilities include:

  • Logging request/response metadata
  • Injecting authentication information
  • Enforcing access control
  • Handling panics
  • Measuring latency

What Middleware Should Not Do

Plumego intentionally discourages using middleware for:

  • Core business logic
  • Complex decision-making tied to domain rules
  • Data persistence
  • Orchestrating workflows

If middleware becomes deeply aware of business rules, boundaries are being violated.


Middleware vs Handler Logic

A useful rule of thumb:

  • Middleware answers “can this request proceed?”
  • Handlers answer “what does this request do?”

If logic answers the second question, it likely belongs in the handler or domain layer.


Error Handling in Middleware

Middleware may encounter errors.

Common strategies include:

  • Writing an error response and stopping the chain
  • Attaching error information to the context
  • Deferring error handling to later middleware

Plumego does not enforce a single error-handling strategy.

However:

  • Error handling must be explicit
  • Hidden or implicit recovery is discouraged

Panic Recovery as Middleware

Panic recovery is a classic middleware use case.

A recovery middleware typically:

  • Uses defer
  • Recovers from panics
  • Logs the error
  • Writes a safe error response

This keeps panic handling:

  • Centralized
  • Predictable
  • Separated from business logic

Middleware and Performance

Middleware adds overhead.

Plumego’s design minimizes this by:

  • Avoiding reflection
  • Avoiding dynamic dispatch
  • Using simple function calls

However, excessive middleware layers still increase latency.

Guidelines:

  • Keep middleware lightweight
  • Avoid heavy computation
  • Push expensive work deeper only when necessary

Middleware Composition Over Inheritance

Plumego favors composition, not inheritance or global hooks.

Instead of:

  • One large middleware doing many things

Prefer:

  • Small, focused middleware functions
  • Clear composition order
  • Explicit intent

This improves readability and testability.


Common Mistakes

Forgetting to Call next()

If next() is not called, the handler will never run.

This is a common source of confusion.

Always verify control flow explicitly.


Writing Responses After next()

If middleware writes a response after calling next(),
ensure that the handler has not already written one.

Double writes lead to undefined behavior.


Using Middleware as a Dependency Injector

Context is not a service container.

Middleware should not inject large dependency graphs into context.


Summary

In Plumego, middleware is:

  • Explicit
  • Ordered
  • Predictable
  • Powerful, but intentionally constrained

Middleware handles cross-cutting concerns and nothing else.

Used correctly, it keeps handlers clean and systems understandable.

Used incorrectly, it becomes a source of hidden complexity.


Next

With middleware understood, the next concept is:

Handler

This explains the role of handlers as the boundary between HTTP and application logic.