Posted on :: Updated on ::

Mux

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("GET /posts",          listPosts)
    mux.HandleFunc("POST /posts",         createPost)
    mux.HandleFunc("GET /posts/{id}",     getPost)
    mux.HandleFunc("PUT /posts/{id}",     updatePost)
    mux.HandleFunc("DELETE /posts/{id}",  deletePost)

    http.ListenAndServe(":8080", mux)
}

Path values

mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")  // new in 1.22
    fmt.Fprintf(w, "User ID: %s", id)
})

HTTP Middleware

Pattern

func exampleMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Your middleware logic goes here...
		next.ServeHTTP(w, r)
	})
}

func fooHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("foo"))
}

func main() {
	mux := http.NewServeMux()
	mux.Handle("/foo", exampleMiddleware(http.HandleFunc(fooHandler)))
	
	log.Fatal(http.ListenAndServe(":3000", mux))
}

To add middleware for all routes, add it on http.ServeMux() (since it implements http.Handler interface).

log.Fatal(http.ListenAndServe(":3000", myMiddleware(mux)))

Chain

type chain []func(http.Handler) http.Handler

func (c chain) thenFunc(h http.HandlerFunc) http.Handler {
    return c.then(h)
}

func (c chain) then(h http.Handler) http.Handler {
    for _, mw := range slices.Backward(c) {
        h = mw(h)
    }
    return h
}

Usage:

mux := http.NewServeMux()

// Create a base middleware chain. 
baseChain := chain{requestID, logRequest}

// Extend the base chain with auth middleware for admin-only routes.
adminChain := append(baseChain, authenticateUser, requireAdminUser)

mux.Handle("GET /static/", spaHandler(http.FileServerFS(ui.Files)))

mux.Handle("GET /", baseChain.thenFunc(home))
mux.Handle("GET /article/{id}", baseChain.thenFunc(showArticle))

mux.Handle("GET /admin", adminChain.thenFunc(showAdminDashboard))

Use cases

  • Check if user is authenticated
  • Check for headers like Content-Type
  • Implement rate limit logic
  • Add http headers in response
  • Log request & response automatically using log/slog

Sources

  • https://www.alexedwards.net/blog/making-and-using-middleware
  • https://www.alexedwards.net/blog/organize-your-go-middleware-without-dependencies