Chapter 10: Middleware
This is one of the most advanced concepts in Go web servers. Let's dissect it carefully.
1 Functions as Values
In Go, a function is a value. You can:
- Store it in a variable.
- Pass it as an argument.
- Return it from another function.
2 The Middleware Signature
func Logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Pre-Processing
fmt.Println("Start")
next.ServeHTTP(w, r) // Pass the baton
// Post-Processing
fmt.Println("End")
})
}Line-by-Line Anatomy
func Logging(next http.Handler) http.Handler:- Input: The Next layer of the onion (the inner handler).
- Output: A New handler that wraps the old one.
return http.HandlerFunc(...):- We are building a new handler on the fly.
func(w, r):- This is the Closure. It captures the
nextvariable from outside.
- This is the Closure. It captures the
next.ServeHTTP(w, r):- Crucial: This calls the original handler.
- If you forget this line, the request stops here. The downstream handler is skipped. Middleware can intentionally send a response itself, such as 401. Returning without writing generally produces an empty 200 response.
If Transport talks to Service, and Service talks to Repository... who checks if the user is logged in? Who measures speed? This is the Middleware.
3 The Matryoshka (Russian Doll)
Middleware is like a Matryoshka doll. You put your Handler inside a Logger. You put the Logger inside an Authenticator. When a request comes in, it has to drill through all the outer layers to reach the center (your logic).
The Chain
When we wrap handlers: Logging(Auth(HomeHandler))
- Request arrives $\rightarrow$ Logging starts.
- Logging calls
next$\rightarrow$ Auth starts. - Auth calls
next$\rightarrow$ HomeHandler (Business Logic). - HomeHandler returns.
- Auth finishes.
- Logging finishes.
🎓 Knowledge Check: What happens if a middleware forgets to call next.ServeHTTP(w, r)?
Answer: The request stops there! It never reaches the next middleware or your business logic. If the middleware returns without writing, the server generally sends an empty 200 response. A timeout requires a separate blocking condition.
