Skip to main content

Code Around Every Handler

Middleware is code that runs around your handlers: before the request reaches them, after the response leaves them, or instead of them. Logging, authentication, rate limiting, compression — all middleware.

The same idea travels under three names: web frameworks say middleware, gRPC says interceptor, some ecosystems say filter. One concept, three vocabularies.

In Go, middleware is a function that takes a handler and returns a wrapped handler — exactly the Decorator pattern from the design patterns group, and a stack of them behaves like a Chain of Responsibility.


A Logging Middleware

withLog wraps any handler: it prints the request coming in, lets the handler work, and prints again on the way out. The handler itself stays completely unaware.

Wrap once, log everything

The wrapped handler serves two different paths and both get logged — the logging is written once, in the wrapper, not in every handler.

Prompt
Write a Go program with a withLog middleware that wraps an http.Handler, printing an arrow line with the method and path before calling the next handler and a done line after. Wrap a mux with two routes, serve with httptest, request both paths and print the responses.
Output: Go program and captured output
Wrap once, log everything

Middleware That Stops the Request

Middleware can also refuse: an auth check that finds no valid key writes 401 Unauthorized and never calls the next handler.

Chained as withLog(withAuth(handler)), the request passes through the layers in order — and the response bubbles back out through them.

An auth layer in the chain

The request without a key is stopped by the auth layer with 401 — the handler never runs. With the key, the request passes the whole chain and reaches the data.

Prompt
Write a Go program with two chained middlewares: withLog printing the request, and withAuth checking the X-API-Key header and answering 401 without calling the next handler when the key is wrong. Wrap a data handler as withLog(withAuth(handler)), serve with httptest, then send one request without the key and one with it, printing both statuses and bodies.
Output: Go program and captured output