0
0
GoHow-ToBeginner · 3 min read

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.Handler that calls next.ServeHTTP inside
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.ServeHTTP without 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.Handler to add reusable logic.
  • Always call next.ServeHTTP(w, r) to continue the chain.
  • Use http.HandlerFunc to 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.