### Complete Alice Middleware Chaining Example Source: https://github.com/justinas/alice/blob/master/README.md Demonstrates a full application setup using Alice to chain multiple middleware functions (throttling, timeout, CSRF protection) before reaching the main application handler. ```go package main import ( "net/http" "time" "github.com/throttled/throttled" "github.com/justinas/alice" "github.com/justinas/nosurf" ) func timeoutHandler(h http.Handler) http.Handler { return http.TimeoutHandler(h, 1*time.Second, "timed out") } func myApp(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello world!")) } func main() { th := throttled.Interval(throttled.PerSec(10), 1, &throttled.VaryBy{Path: true}, 50) myHandler := http.HandlerFunc(myApp) chain := alice.New(th.Throttle, timeoutHandler, nosurf.NewPure).Then(myHandler) http.ListenAndServe(":8000", chain) } ``` -------------------------------- ### Go HTTP Server with Alice Middleware Source: https://context7.com/justinas/alice/llms.txt This comprehensive example demonstrates building a production-ready HTTP server with multiple middleware layers, reusable chains, and different route configurations using the Alice library. ```go package main import ( "encoding/json" "log" "net/http" "time" "github.com/justinas/alice" ) // Logging middleware - logs request method, path, and duration func loggingMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() h.ServeHTTP(w, r) log.Printf("[%s] %s %v", r.Method, r.URL.Path, time.Since(start)) }) } // Recovery middleware - catches panics and returns 500 func recoveryMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { log.Printf("panic recovered: %v", err) http.Error(w, `{"error": "Internal Server Error"}`, http.StatusInternalServerError) } }() h.ServeHTTP(w, r) }) } // CORS middleware - adds CORS headers func corsMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } h.ServeHTTP(w, r) }) } // JSON content type middleware func jsonMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") h.ServeHTTP(w, r) }) } // Auth middleware - validates authorization header func authMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if token != "Bearer secret-token" { w.WriteHeader(http.StatusUnauthorized) json.NewEncoder(w).Encode(map[string]string{"error": "Unauthorized"}) return } h.ServeHTTP(w, r) }) } func main() { // Base chain for all routes baseChain := alice.New(recoveryMiddleware, loggingMiddleware, corsMiddleware) // API chain adds JSON content type apiChain := baseChain.Append(jsonMiddleware) // Protected chain adds authentication protectedChain := apiChain.Append(authMiddleware) // Public endpoints http.Handle("/health", apiChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(map[string]string{"status": "healthy"}) })) http.Handle("/api/public", apiChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(map[string]string{"message": "Public data"}) })) // Protected endpoints http.Handle("/api/user", protectedChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(map[string]interface{}{ "id": 1, "name": "John Doe", "email": "john@example.com", }) })) http.Handle("/api/admin", protectedChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(map[string]string{"message": "Admin data"}) })) log.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) } ``` ```bash curl http://localhost:8080/health # Output: {"status":"healthy"} ``` ```bash curl http://localhost:8080/api/public # Output: {"message":"Public data"} ``` ```bash curl http://localhost:8080/api/user # Output: {"error":"Unauthorized"} ``` ```bash curl -H "Authorization: Bearer secret-token" http://localhost:8080/api/user # Output: {"email":"john@example.com","id":1,"name":"John Doe"} ``` -------------------------------- ### Custom Middleware Constructor Example Source: https://github.com/justinas/alice/blob/master/README.md Shows how to create a custom middleware constructor function that adapts a standard http.Handler to the expected signature. ```go func myStripPrefix(h http.Handler) http.Handler { return http.StripPrefix("/old", h) } ``` -------------------------------- ### Using ThenFunc with http.HandlerFunc Source: https://context7.com/justinas/alice/llms.txt Demonstrates how ThenFunc simplifies adding http.HandlerFunc to an Alice chain, avoiding manual wrapping. ```go package main import ( "fmt" "net/http" "github.com/justinas/alice" ) func corsMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE") h.ServeHTTP(w, r) }) } func main() { chain := alice.New(corsMiddleware) // Using ThenFunc - cleaner syntax for handler functions handler := chain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Response with CORS headers") }) // Equivalent to: // handler := chain.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // fmt.Fprintln(w, "Response with CORS headers") // })) http.Handle("/", handler) http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Composing Chains with Extend Source: https://context7.com/justinas/alice/llms.txt Illustrates how to use Extend to combine two existing middleware chains into a new one, preserving immutability of the originals. ```go package main import ( "fmt" "net/http" "github.com/justinas/alice" ) func loggingMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[log]") h.ServeHTTP(w, r) }) } func rateLimitMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[ratelimit]") h.ServeHTTP(w, r) }) } func authMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[auth]") h.ServeHTTP(w, r) }) } func adminMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[admin]") h.ServeHTTP(w, r) }) } func main() { // Define reusable middleware stacks commonChain := alice.New(loggingMiddleware, rateLimitMiddleware) securityChain := alice.New(authMiddleware, adminMiddleware) // Compose chains together // Request flow: logging -> rateLimit -> auth -> admin -> handler adminChain := commonChain.Extend(securityChain) // All original chains remain unchanged // commonChain: logging -> rateLimit // securityChain: auth -> admin // adminChain: logging -> rateLimit -> auth -> admin publicHandler := commonChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[public]") }) adminHandler := adminChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[admin-page]") }) http.Handle("/public", publicHandler) // Output: [log][ratelimit][public] http.Handle("/admin", adminHandler) // Output: [log][ratelimit][auth][admin][admin-page] http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Transforming Nested Middleware to Alice Chain Source: https://github.com/justinas/alice/blob/master/README.md Illustrates the syntactic transformation from nested middleware calls to using the Alice library's chaining mechanism. ```go Middleware1(Middleware2(Middleware3(App))) ``` ```go alice.New(Middleware1, Middleware2, Middleware3).Then(App) ``` -------------------------------- ### Initialize Middleware Chains with New Source: https://context7.com/justinas/alice/llms.txt The New function stores middleware constructors without executing them. Chains are immutable and can be safely reused. ```go package main import ( "log" "net/http" "time" "github.com/justinas/alice" ) func loggingMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() h.ServeHTTP(w, r) log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start)) }) } func recoveryMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }() h.ServeHTTP(w, r) }) } func main() { // Create a new chain with multiple middleware chain := alice.New(loggingMiddleware, recoveryMiddleware) // Chain can be reused - constructors are stored, not executed yet log.Println("Chain created with 2 middleware constructors") } ``` -------------------------------- ### Extending a Chain with Append Source: https://context7.com/justinas/alice/llms.txt Shows how to use Append to add new middleware to an existing chain, creating a new immutable chain. ```go package main import ( "fmt" "net/http" "github.com/justinas/alice" ) func middleware1(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "[m1]") h.ServeHTTP(w, r) }) } func middleware2(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "[m2]") h.ServeHTTP(w, r) }) } func middleware3(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "[m3]") h.ServeHTTP(w, r) }) } func main() { // Base chain with common middleware baseChain := alice.New(middleware1, middleware2) // Extended chain with additional middleware // Original baseChain remains unchanged (immutable) extendedChain := baseChain.Append(middleware3) // baseChain: middleware1 -> middleware2 -> handler // Output: [m1][m2][app] baseHandler := baseChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[app]") }) // extendedChain: middleware1 -> middleware2 -> middleware3 -> handler // Output: [m1][m2][m3][app] extendedHandler := extendedChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[app]") }) http.Handle("/base", baseHandler) http.Handle("/extended", extendedHandler) http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Define Middleware Constructors in Go Source: https://context7.com/justinas/alice/llms.txt Middleware must accept an http.Handler and return an http.Handler. This pattern allows wrapping standard library functions or custom logic. ```go package main import ( "net/http" ) // Constructor signature: func(http.Handler) http.Handler // Create a middleware that adds a custom header to all responses func addHeaderMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Custom-Header", "middleware-applied") h.ServeHTTP(w, r) }) } // Wrap standard library functions as middleware constructors func myStripPrefix(h http.Handler) http.Handler { return http.StripPrefix("/api", h) } ``` -------------------------------- ### Finalize Middleware Chains with Then Source: https://context7.com/justinas/alice/llms.txt The Then method executes the chain and returns an http.Handler. Passing nil to Then defaults to http.DefaultServeMux. ```go package main import ( "fmt" "net/http" "time" "github.com/justinas/alice" ) func timeoutMiddleware(h http.Handler) http.Handler { return http.TimeoutHandler(h, 5*time.Second, "Request timed out") } func authMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if token == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } h.ServeHTTP(w, r) }) } func main() { // Final application handler myApp := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, authenticated user!") }) // Create chain and finalize with Then() // Request flow: timeoutMiddleware -> authMiddleware -> myApp handler := alice.New(timeoutMiddleware, authMiddleware).Then(myApp) // Use the chained handler http.Handle("/api/", handler) http.ListenAndServe(":8080", nil) } // Reusing chains for multiple handlers func setupRoutes() { stdChain := alice.New(timeoutMiddleware, authMiddleware) // Same middleware stack, different handlers indexHandler := stdChain.Then(http.HandlerFunc(handleIndex)) userHandler := stdChain.Then(http.HandlerFunc(handleUser)) http.Handle("/", indexHandler) http.Handle("/user", userHandler) } func handleIndex(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Index page") } func handleUser(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "User page") } ``` -------------------------------- ### Extend Middleware Chains Source: https://context7.com/justinas/alice/llms.txt The Extend method composes two middleware chains by appending the constructors of one chain to another. It returns a new chain, leaving both original chains unmodified. ```APIDOC ## Extend ### Description `Extend` extends a chain by appending another chain's constructors. It returns a new chain, leaving both original chains untouched. This is useful for composing predefined middleware stacks. ### Method `Extend` is a method on a middleware chain. ### Endpoint N/A (This is a library function, not an HTTP endpoint). ### Parameters #### Request Body - **otherChain** (alice.Chain) - Required - The chain whose constructors will be appended. ### Request Example ```go package main import ( "fmt" "net/http" "github.com/justinas/alice" ) func loggingMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[log]") h.ServeHTTP(w, r) }) } func rateLimitMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[ratelimit]") h.ServeHTTP(w, r) }) } func authMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[auth]") h.ServeHTTP(w, r) }) } func adminMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Print("[admin]") h.ServeHTTP(w, r) }) } func main() { // Define reusable middleware stacks commonChain := alice.New(loggingMiddleware, rateLimitMiddleware) securityChain := alice.New(authMiddleware, adminMiddleware) // Compose chains together // Request flow: logging -> rateLimit -> auth -> admin -> handler adminChain := commonChain.Extend(securityChain) // All original chains remain unchanged publicHandler := commonChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[public]") }) adminHandler := adminChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[admin-page]") }) http.Handle("/public", publicHandler) // Output: [log][ratelimit][public] http.Handle("/admin", adminHandler) // Output: [log][ratelimit][auth][admin][admin-page] http.ListenAndServe(":8080", nil) } ``` ### Response #### Success Response (200) - The response is generated by the final handler function after all middleware from both the original and extended chains have executed in order. ``` -------------------------------- ### Append Middleware Source: https://context7.com/justinas/alice/llms.txt The Append method extends an existing middleware chain by adding new constructors to the end. It returns a new chain, ensuring the original chain remains unchanged. ```APIDOC ## Append ### Description `Append` extends a chain by adding specified constructors as the last ones in the request flow. It returns a new chain, leaving the original untouched (immutability). ### Method `Append` is a method on a middleware chain. ### Endpoint N/A (This is a library function, not an HTTP endpoint). ### Parameters #### Request Body - **constructors** (...alice.Constructor) - Required - One or more middleware constructors to append to the chain. ### Request Example ```go package main import ( "fmt" "net/http" "github.com/justinas/alice" ) func middleware1(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "[m1]") h.ServeHTTP(w, r) }) } func middleware2(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "[m2]") h.ServeHTTP(w, r) }) } func middleware3(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "[m3]") h.ServeHTTP(w, r) }) } func main() { // Base chain with common middleware baseChain := alice.New(middleware1, middleware2) // Extended chain with additional middleware // Original baseChain remains unchanged (immutable) extendedChain := baseChain.Append(middleware3) // baseChain: middleware1 -> middleware2 -> handler baseHandler := baseChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[app]") }) // extendedChain: middleware1 -> middleware2 -> middleware3 -> handler extendedHandler := extendedChain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "[app]") }) http.Handle("/base", baseHandler) // Output: [m1][m2][app] http.Handle("/extended", extendedHandler) // Output: [m1][m2][m3][app] http.ListenAndServe(":8080", nil) } ``` ### Response #### Success Response (200) - The response is generated by the final handler function after all middleware in the appended chain have executed. ``` -------------------------------- ### ThenFunc Usage Source: https://context7.com/justinas/alice/llms.txt ThenFunc allows you to add an http.HandlerFunc directly to the end of a middleware chain, simplifying the process compared to manually wrapping it with http.HandlerFunc. ```APIDOC ## ThenFunc ### Description `ThenFunc` works identically to `Then`, but accepts an `http.HandlerFunc` instead of an `http.Handler`. This is a convenience method that eliminates the need to wrap handler functions manually. ### Method `ThenFunc` is a method on a middleware chain. ### Endpoint N/A (This is a library function, not an HTTP endpoint). ### Parameters #### Request Body - **handlerFunc** (http.HandlerFunc) - Required - The handler function to be executed after all middleware. ### Request Example ```go package main import ( "fmt" "net/http" "github.com/justinas/alice" ) func corsMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE") h.ServeHTTP(w, r) }) } func main() { chain := alice.New(corsMiddleware) // Using ThenFunc - cleaner syntax for handler functions handler := chain.ThenFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Response with CORS headers") }) http.Handle("/", handler) http.ListenAndServe(":8080", nil) } ``` ### Response #### Success Response (200) - The response is generated by the provided `http.HandlerFunc` after all middleware in the chain have executed. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.