How to Use Middleware in Go: Simple Guide with Examples
In Go, middleware is a function that wraps an
http.Handler to add extra behavior before or after the main handler runs. You create middleware by writing a function that takes and returns an http.Handler, then use it to wrap your handlers.Syntax
Middleware in Go is a function that takes an http.Handler and returns a new http.Handler. This lets you add extra steps before or after the original handler runs.
next http.Handler: the original handler to wrap- Returns a new
http.Handlerthat callsnext.ServeHTTPinside
go
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Code before calling next
next.ServeHTTP(w, r)
// Code after calling next
})
}Example
This example shows a simple logging middleware that prints the request path before calling the main handler.
go
package main import ( "fmt" "net/http" ) // LoggingMiddleware prints the request path func LoggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println("Request path:", r.URL.Path) next.ServeHTTP(w, r) }) } func HelloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, world!") } func main() { hello := http.HandlerFunc(HelloHandler) http.Handle("/", LoggingMiddleware(hello)) fmt.Println("Server started at :8080") http.ListenAndServe(":8080", nil) }
Output
Server started at :8080
Request path: /
Common Pitfalls
Common mistakes when using middleware in Go include:
- Not calling
next.ServeHTTP, which stops the request chain. - Modifying the response before calling
next.ServeHTTPwithout proper care, which can cause unexpected behavior. - Forgetting to wrap handlers properly, leading to middleware not running.
go
/* Wrong: middleware does not call next handler */ func BadMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Missing next.ServeHTTP call fmt.Println("Middleware ran but did not call next") }) } /* Right: calls next handler */ func GoodMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Println("Middleware before next") next.ServeHTTP(w, r) fmt.Println("Middleware after next") }) }
Quick Reference
Tips for using middleware in Go:
- Middleware wraps
http.Handlerto add reusable logic. - Always call
next.ServeHTTP(w, r)to continue the chain. - Use
http.HandlerFuncto create inline handlers easily. - Chain multiple middleware by wrapping handlers multiple times.
Key Takeaways
Middleware in Go wraps http.Handler to add extra behavior around requests.
Always call next.ServeHTTP inside your middleware to continue processing.
Use http.HandlerFunc to create middleware functions easily.
Chain middleware by wrapping handlers multiple times for layered effects.