Skip to main content
Middleware wraps your handlers to run code before or after them, which is a natural home for concerns like authentication, logging, and transactions. In Copper, a middleware is anything that implements a single-method interface:

Writing Middleware

A middleware is typically a struct so that its dependencies can be injected by wire. For example, the following middleware protects internal routes with a bearer token:
pkg/rockets/middleware.go
For simple middleware without dependencies, you may wrap a plain function with chttp.HandleMiddleware:

Registering Middleware

You may attach middleware to a single route using the Middlewares field:
To run middleware on every request, add it to GlobalMiddlewares in pkg/app/handler.go:
pkg/app/handler.go
Middleware runs in the order it is listed, so the first entry sees the request first. Global middleware always runs before route middleware.

Built-in Middleware

Copper ships the middleware most apps need, already wired into new projects:
  • chttp.SetRequestIDInCtxMiddleware() puts a unique request ID in the context. You may read it anywhere with chttp.GetRequestID(ctx).
  • chttp.RequestLoggerMiddleware logs every request’s method, path, status code, and duration, and also records the built-in http_requests_total and http_request_duration_seconds Prometheus metrics. See Metrics.
  • csql.TxMiddleware wraps mutating requests in a database transaction that commits or rolls back based on the response status. See Transactions.
Panic recovery is built into the handler itself, so there is no recovery middleware to register. A panicking handler is logged with its stack trace and the client receives a 500; you never need to add this yourself.