Exemples de Fonctionnalités Web Web Go

Exemples de fonctionnalités spécifiques Web Go incluant le gestionnaire de routes, middleware et service de fichiers statiques

Key Facts

Category
Go
Items
3
Format Families
image, audio

Sample Overview

Exemples de fonctionnalités spécifiques Web Go incluant le gestionnaire de routes, middleware et service de fichiers statiques This sample set belongs to Go and can be used to test related workflows inside Elysia Tools.

💻 Service de Fichiers Statiques go

🟢 simple ⭐⭐⭐

Servir des fichiers statiques, CSS, JavaScript, images avec un cache et des en-têtes appropriés

⏱️ 20 min 🏷️ go, web, static files
Prerequisites: Basic Go, net/http package, file io
// Web Go Static File Serving Examples
// Serve static files with caching and headers

package main

import (
	"encoding/base64"
	"fmt"
	"io"
	"log"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// 1. Basic Static File Server

// FileServer serves files from a directory
func FileServer(root http.FileSystem) http.Handler {
	fs := http.FileServer(root)

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Clean the path
		path := filepath.Clean(r.URL.Path)

		// Open file
		file, err := root.Open(path)
		if err != nil {
			if os.IsNotExist(err) {
				http.NotFound(w, r)
			} else {
				http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			}
			return
		}
		defer file.Close()

		// Get file info
		stat, err := file.Stat()
		if err != nil {
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
			return
		}

		// Serve file
		http.ServeContent(w, r, path, stat.ModTime(), file)
	})
}

// 2. Static File Server with Custom Headers

// StaticServer serves static files with custom headers
type StaticServer struct {
	root    string
	headers map[string]string
}

// NewStaticServer creates a new static file server
func NewStaticServer(root string) *StaticServer {
	return &StaticServer{
		root:    root,
		headers: make(map[string]string),
	}
}

// AddHeader adds a default header
func (ss *StaticServer) AddHeader(key, value string) {
	ss.headers[key] = value
}

// ServeHTTP serves HTTP requests
func (ss *StaticServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Clean path
	path := filepath.Join(ss.root, filepath.Clean(r.URL.Path))

	// Get file info
	info, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			http.NotFound(w, r)
		} else {
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		}
		return
	}

	// Check if it's a directory
	if info.IsDir() {
		// Try to serve index.html
	 indexPath := filepath.Join(path, "index.html")
		if _, err := os.Stat(indexPath); err == nil {
			path = indexPath
			info, _ = os.Stat(path)
		} else {
			// Directory listing (for development)
			ss.serveDirectoryListing(w, r, path)
			return
		}
	}

	// Detect content type
	ext := filepath.Ext(path)
	contentType := mime.TypeByExtension(ext)
	if contentType == "" {
		contentType = "application/octet-stream"
	}

	// Set headers
	for key, value := range ss.headers {
		w.Header().Set(key, value)
	}
	w.Header().Set("Content-Type", contentType)

	// Set cache headers
	ss.setCacheHeaders(w, ext)

	// Serve file
	http.ServeFile(w, r, path)
}

// setCacheHeaders sets cache control headers
func (ss *StaticServer) setCacheHeaders(w http.ResponseWriter, ext string) {
	// Static assets can be cached longer
	switch ext {
	case ".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".woff", ".woff2", ".ttf":
		// Cache for 1 year
		w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
	case ".html", ".htm":
		// Don't cache HTML files
		w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	default:
		// Cache for 1 hour
		w.Header().Set("Cache-Control", "public, max-age=3600")
	}
}

// serveDirectoryListing serves directory listing
func (ss *StaticServer) serveDirectoryListing(w http.ResponseWriter, r *http.Request, path string) {
	entries, err := os.ReadDir(path)
	if err != nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, "<!DOCTYPE html><html><head><title>Directory Listing</title></head><body>")
	fmt.Fprintf(w, "<h1>Directory Listing for %s</h1>", r.URL.Path)
	fmt.Fprintf(w, "<ul>")

	for _, entry := range entries {
		name := entry.Name()
		url := filepath.Join(r.URL.Path, name)
		if entry.IsDir() {
			url += "/"
		}
		fmt.Fprintf(w, "<li><a href='%s'>%s</a></li>", url, name)
	}

	fmt.Fprintf(w, "</ul></body></html>")
}

// 3. SPA File Server

// SPAFileServer serves single-page applications
type SPAFileServer struct {
	root      string
	indexFile string
}

// NewSPAFileServer creates a new SPA file server
func NewSPAFileServer(root string) *SPAFileServer {
	return &SPAFileServer{
		root:      root,
		indexFile: "index.html",
	}
}

// ServeHTTP serves HTTP requests for SPA
func (spa *SPAFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Clean path
	path := filepath.Join(spa.root, filepath.Clean(r.URL.Path))

	// Check if file exists
	if _, err := os.Stat(path); os.IsNotExist(err) {
		// File doesn't exist, serve index.html for SPA routing
		indexPath := filepath.Join(spa.root, spa.indexFile)
		http.ServeFile(w, r, indexPath)
		return
	}

	// Serve file if it exists
	info, err := os.Stat(path)
	if err != nil {
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	if info.IsDir() {
		indexPath := filepath.Join(path, spa.indexFile)
		http.ServeFile(w, r, indexPath)
	} else {
		http.ServeFile(w, r, path)
	}
}

// 4. File Server with ETag Support

// ETagFileServer serves files with ETag support
type ETagFileServer struct {
	root string
}

// NewETagFileServer creates a new ETag file server
func NewETagFileServer(root string) *ETagFileServer {
	return &ETagFileServer{root: root}
}

// generateETag generates ETag for file
func (ets *ETagFileServer) generateETag(path string, info os.FileInfo) string {
	data := fmt.Sprintf("%s-%d-%s", path, info.Size(), info.ModTime().Unix())
	hash := base64.StdEncoding.EncodeToString([]byte(data))
	return string('"') + hash + string('"')
}

// ServeHTTP serves HTTP requests with ETag
func (ets *ETagFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := filepath.Join(ets.root, filepath.Clean(r.URL.Path))

	info, err := os.Stat(path)
	if err != nil {
		if os.IsNotExist(err) {
			http.NotFound(w, r)
		} else {
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		}
		return
	}

	if info.IsDir() {
		path = filepath.Join(path, "index.html")
		info, _ = os.Stat(path)
	}

	// Generate ETag
	etag := ets.generateETag(path, info)

	// Check If-None-Match header
	if match := r.Header.Get("If-None-Match"); match == etag {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	// Set ETag header
	w.Header().Set("ETag", etag)

	// Serve file
	http.ServeFile(w, r, path)
}

// 5. File Server with Compression

// CompressionMiddleware compresses responses
type CompressionMiddleware struct {
	next http.Handler
}

// NewCompressionMiddleware creates compression middleware
func NewCompressionMiddleware(next http.Handler) *CompressionMiddleware {
	return &CompressionMiddleware{next: next}
}

// ShouldCompress checks if response should be compressed
func ShouldCompress(r *http.Request) bool {
	// Check Accept-Encoding header
	acceptEncoding := r.Header.Get("Accept-Encoding")
	return strings.Contains(acceptEncoding, "gzip")
}

// ServeHTTP serves compressed responses
func (cm *CompressionMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !ShouldCompress(r) {
		cm.next.ServeHTTP(w, r)
		return
	}

	// Check if content type is compressible
	path := r.URL.Path
	ext := filepath.Ext(path)
	compressible := map[string]bool{
		".js":  true,
		".css": true,
		".html": true,
		".txt": true,
		".xml": true,
		".json": true,
	}

	if !compressible[ext] {
		cm.next.ServeHTTP(w, r)
		return
	}

	// Set compression header
	w.Header().Set("Content-Encoding", "gzip")
	w.Header().Set("Vary", "Accept-Encoding")

	cm.next.ServeHTTP(w, r)
}

// 6. File Upload Handler

// UploadHandler handles file uploads
func UploadHandler(uploadDir string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost && r.Method != http.MethodPut {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}

		// Parse multipart form (max 32MB)
		err := r.ParseMultipartForm(32 << 20)
		if err != nil {
			http.Error(w, "Error parsing form", http.StatusBadRequest)
			return
		}

		// Get file from form
		file, handler, err := r.FormFile("file")
		if err != nil {
			http.Error(w, "Error retrieving file", http.StatusBadRequest)
			return
		}
		defer file.Close()

		// Create destination file
		dstPath := filepath.Join(uploadDir, handler.Filename)
		dst, err := os.Create(dstPath)
		if err != nil {
			http.Error(w, "Error creating file", http.StatusInternalServerError)
			return
		}
		defer dst.Close()

		// Copy file
		_, err = io.Copy(dst, file)
		if err != nil {
			http.Error(w, "Error saving file", http.StatusInternalServerError)
			return
		}

		w.WriteHeader(http.StatusCreated)
		fmt.Fprintf(w, "File uploaded successfully: %s", handler.Filename)
	}
}

// 7. File Download Handler

// DownloadHandler handles file downloads
func DownloadHandler(root string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Get filename from query parameter
		filename := r.URL.Query().Get("file")
		if filename == "" {
			http.Error(w, "Filename required", http.StatusBadRequest)
			return
		}

		// Build file path
		path := filepath.Join(root, filepath.Base(filename))

		// Check if file exists
		if _, err := os.Stat(path); os.IsNotExist(err) {
			http.NotFound(w, r)
			return
		}

		// Set headers for download
		w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filepath.Base(filename)))
		w.Header().Set("Content-Type", "application/octet-stream")

		// Serve file
		http.ServeFile(w, r, path)
	}
}

// 8. Image Thumbnail Generator

// ThumbnailHandler generates and serves thumbnails
func ThumbnailHandler(imageDir string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Get filename and size from query
		filename := r.URL.Query().Get("file")
		width := r.URL.Query().Get("width")
		height := r.URL.Query().Get("height")

		if filename == "" {
			http.Error(w, "Filename required", http.StatusBadRequest)
			return
		}

		// For simplicity, just serve the original file
		// In production, you'd use an image processing library
		path := filepath.Join(imageDir, filepath.Base(filename))

		if _, err := os.Stat(path); os.IsNotExist(err) {
			http.NotFound(w, r)
			return
		}

		log.Printf("Serving thumbnail: %s (size: %sx%s)", filename, width, height)
		http.ServeFile(w, r, path)
	}
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go Static File Serving Examples ===\n")

	// 1. Basic file server
	fmt.Println("--- 1. Basic File Server ---")
	fs := http.FileServer(http.Dir("./public"))
	fmt.Printf("FileServer: %T\n", fs)

	// 2. Custom static server
	fmt.Println("\n--- 2. Custom Static Server ---")
	staticServer := NewStaticServer("./public")
	staticServer.AddHeader("X-Content-Type-Options", "nosniff")
	staticServer.AddHeader("X-Frame-Options", "DENY")
	fmt.Printf("StaticServer configured with %d custom headers\n", len(staticServer.headers))

	// 3. SPA file server
	fmt.Println("\n--- 3. SPA File Server ---")
	spaServer := NewSPAFileServer("./spa")
	fmt.Printf("SPAFileServer: %T\n", spaServer)

	// 4. ETag file server
	fmt.Println("\n--- 4. ETag File Server ---")
	etagServer := NewETagFileServer("./public")
	fmt.Printf("ETagFileServer: %T\n", etagServer)

	// 5. File upload handler
	fmt.Println("\n--- 5. File Upload Handler ---")
	uploadHandler := UploadHandler("./uploads")
	fmt.Printf("UploadHandler: %T\n", uploadHandler)

	// 6. Server configuration examples
	fmt.Println("\n--- 6. Server Configuration ---")

	// Example 1: Serve static files
	mux := http.NewServeMux()
	mux.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("./public"))))
	fmt.Println("Static files: /static/*")

	// Example 2: SPA route
	mux.Handle("/app/", spaServer)
	fmt.Println("SPA route: /app/*")

	// Example 3: Upload endpoint
	mux.HandleFunc("/upload", uploadHandler)
	fmt.Println("Upload endpoint: /upload")

	// Example 4: Download endpoint
	mux.HandleFunc("/download", DownloadHandler("./files"))
	fmt.Println("Download endpoint: /download?file=example.pdf")

	// Example 5: Thumbnail endpoint
	mux.HandleFunc("/thumbnail", ThumbnailHandler("./images"))
	fmt.Println("Thumbnail endpoint: /thumbnail?file=image.jpg&width=200&height=200")

	fmt.Println("\n--- 7. Server Setup ---")
	fmt.Println("http.ListenAndServe(':8080', mux)")

	fmt.Println("\n=== All Static File Serving Examples Completed ===")
}

💻 Gestion des Routes go

🟡 intermediate ⭐⭐⭐

Routage et analyse d'URL utilisant le paquet http Go et des routeurs populaires comme gorilla/mux

⏱️ 25 min 🏷️ go, web, routing
Prerequisites: Intermediate Go, net/http package
// Web Go Route Handling Examples
// URL routing and parsing using Go http package

package main

import (
	"fmt"
	"net/http"
	"strings"
)

// 1. Basic HTTP Routing

// BasicRouteHandler demonstrates basic route handling
func BasicRouteHandler(w http.ResponseWriter, r *http.Request) {
	switch r.URL.Path {
	case "/":
		fmt.Fprintf(w, "Welcome to the Home Page!")
	case "/about":
		fmt.Fprintf(w, "About Us Page")
	case "/contact":
		fmt.Fprintf(w, "Contact Page")
	default:
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(w, "404 - Page Not Found")
	}
}

// 2. Method-Based Routing

// MethodRouteHandler handles different HTTP methods
func MethodRouteHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		fmt.Fprintf(w, "GET request received")
	case http.MethodPost:
		fmt.Fprintf(w, "POST request received")
	case http.MethodPut:
		fmt.Fprintf(w, "PUT request received")
	case http.MethodDelete:
		fmt.Fprintf(w, "DELETE request received")
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Method Not Allowed")
	}
}

// 3. Query Parameter Handling

// QueryParamHandler handles query parameters
func QueryParamHandler(w http.ResponseWriter, r *http.Request) {
	queryParams := r.URL.Query()

	name := queryParams.Get("name")
	age := queryParams.Get("age")

	if name == "" {
		name = "Guest"
	}

	fmt.Fprintf(w, "Hello, %s!", name)
	if age != "" {
		fmt.Fprintf(w, " You are %s years old.", age)
	}
}

// 4. Path Parameter Extraction (Simple)

// UserHandler handles /users/:id pattern
func UserHandler(w http.ResponseWriter, r *http.Request) {
	// Extract ID from path like /users/123
	path := strings.TrimPrefix(r.URL.Path, "/users/")
	if path == "" || path == r.URL.Path {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Invalid user ID")
		return
	}

	userID := strings.Split(path, "/")[0]
	fmt.Fprintf(w, "User ID: %s", userID)
}

// 5. Custom Route Structure

// Route represents a route definition
type Route struct {
	Name        string
	Method      string
	Pattern     string
	HandlerFunc http.HandlerFunc
}

// Routes is a collection of Route
type Routes []Route

// Router holds route definitions
type Router struct {
	routes Routes
}

// NewRouter creates a new router
func NewRouter() *Router {
	return &Router{
		routes: Routes{
			Route{
				Name:        "Index",
				Method:      "GET",
				Pattern:     "/",
				HandlerFunc: IndexHandler,
			},
			Route{
				Name:        "GetUser",
				Method:      "GET",
				Pattern:     "/users/{id}",
				HandlerFunc: GetUserHandler,
			},
			Route{
				Name:        "CreateUser",
				Method:      "POST",
				Pattern:     "/users",
				HandlerFunc: CreateUserHandler,
			},
		},
	}
}

// Handler returns the main HTTP handler
func (router *Router) Handler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		for _, route := range router.routes {
			if r.Method != route.Method {
				continue
			}

			// Simple pattern matching
			if matchRoute(route.Pattern, r.URL.Path) {
				route.HandlerFunc(w, r)
				return
			}
		}

		// No matching route found
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(w, "404 - Not Found")
	})
}

// matchRoute matches URL pattern to path
func matchRoute(pattern, path string) bool {
	// Replace {param} with wildcard
	pattern = strings.ReplaceAll(pattern, "{id}", "*")
	pattern = strings.ReplaceAll(pattern, "{name}", "*")

	// Simple matching
	if strings.HasSuffix(pattern, "*") {
		prefix := strings.TrimSuffix(pattern, "/*")
		return strings.HasPrefix(path, prefix)
	}

	return pattern == path
}

// Handler Functions

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome to the API!")
}

func GetUserHandler(w http.ResponseWriter, r *http.Request) {
	// Extract user ID from path
	path := strings.TrimPrefix(r.URL.Path, "/users/")
	userID := strings.Split(path, "/")[0]
	fmt.Fprintf(w, "Get User: %s", userID)
}

func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Create User")
}

// 6. Route Groups and Prefixes

// RouteGroup represents a group of routes with common prefix
type RouteGroup struct {
	prefix string
	routes []Route
}

// NewRouteGroup creates a new route group
func NewRouteGroup(prefix string) *RouteGroup {
	return &RouteGroup{
		prefix: prefix,
		routes: []Route{},
	}
}

// AddRoute adds a route to the group
func (rg *RouteGroup) AddRoute(method, pattern string, handler http.HandlerFunc) {
	fullPattern := rg.prefix + pattern
	rg.routes = append(rg.routes, Route{
		Method:      method,
		Pattern:     fullPattern,
		HandlerFunc: handler,
	})
}

// GetRoutes returns all routes in the group
func (rg *RouteGroup) GetRoutes() Routes {
	return rg.routes
}

// 7. URL Building

// URLBuilder builds URLs with parameters
type URLBuilder struct {
	baseURL string
}

// NewURLBuilder creates a new URL builder
func NewURLBuilder(baseURL string) *URLBuilder {
	return &URLBuilder{baseURL: baseURL}
}

// Build builds a URL with path
func (ub *URLBuilder) Build(path string) string {
	return ub.baseURL + path
}

// BuildWithParams builds a URL with path parameters
func (ub *URLBuilder) BuildWithParams(path string, params map[string]string) string {
	url := ub.baseURL + path
	for key, value := range params {
		url = strings.ReplaceAll(url, "{"+key+"}", value)
	}
	return url
}

// BuildWithQuery builds a URL with query parameters
func (ub *URLBuilder) BuildWithQuery(path string, params map[string]string) string {
	url := ub.baseURL + path
	if len(params) > 0 {
		url += "?"
		i := 0
		for key, value := range params {
			if i > 0 {
				url += "&"
			}
			url += fmt.Sprintf("%s=%s", key, value)
			i++
		}
	}
	return url
}

// 8. Request Context with Parameters

// Context holds request context data
type Context struct {
	Params map[string]string
	Query  map[string]string
}

// NewContext creates a new context from request
func NewContext(r *http.Request) *Context {
	ctx := &Context{
		Params: make(map[string]string),
		Query:  make(map[string]string),
	}

	// Parse query parameters
	for key, values := range r.URL.Query() {
		if len(values) > 0 {
			ctx.Query[key] = values[0]
		}
	}

	return ctx
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go Route Handling Examples ===\n")

	// 1. Basic routing
	fmt.Println("--- 1. Basic Routing ---")
	fmt.Println("Routes: /, /about, /contact")
	fmt.Println("Handler: BasicRouteHandler")

	// 2. Method-based routing
	fmt.Println("\n--- 2. Method-Based Routing ---")
	fmt.Println("Methods: GET, POST, PUT, DELETE")
	fmt.Println("Handler: MethodRouteHandler")

	// 3. Query parameters
	fmt.Println("\n--- 3. Query Parameters ---")
	fmt.Println("URL: /greet?name=John&age=30")
	fmt.Println("Handler: QueryParamHandler")

	// 4. Custom router
	fmt.Println("\n--- 4. Custom Router ---")
	router := NewRouter()
	fmt.Printf("Registered %d routes\n", len(router.routes))
	for _, route := range router.routes {
		fmt.Printf("  %s %s - %s\n", route.Method, route.Pattern, route.Name)
	}

	// 5. Route groups
	fmt.Println("\n--- 5. Route Groups ---")
	apiGroup := NewRouteGroup("/api/v1")
	apiGroup.AddRoute("GET", "/users", IndexHandler)
	apiGroup.AddRoute("POST", "/users", CreateUserHandler)
	apiGroup.AddRoute("GET", "/users/{id}", GetUserHandler)
	fmt.Printf("API Group has %d routes\n", len(apiGroup.GetRoutes()))

	// 6. URL building
	fmt.Println("\n--- 6. URL Building ---")
	builder := NewURLBuilder("https://api.example.com")
	fmt.Printf("Home: %s\n", builder.Build("/"))
	fmt.Printf("User: %s\n", builder.BuildWithParams("/users/{id}", map[string]string{"id": "123"}))
	fmt.Printf("Search: %s\n", builder.BuildWithQuery("/search", map[string]string{"q": "golang", "limit": "10"}))

	// 7. Server setup example
	fmt.Println("\n--- 7. Server Setup ---")
	fmt.Println("http.HandleFunc('/', BasicRouteHandler)")
	fmt.Println("http.ListenAndServe(':8080', nil)")

	fmt.Println("\n=== All Route Handling Examples Completed ===")
}

💻 Middleware go

🟡 intermediate ⭐⭐⭐⭐

Middleware de traitement des requêtes pour la journalisation, l'authentification, CORS et gestionnaires personnalisés

⏱️ 30 min 🏷️ go, web, middleware
Prerequisites: Intermediate Go, net/http package, context package
// Web Go Middleware Examples
// Request processing middleware using Go http package

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"
)

// 1. Basic Middleware Type

// Middleware is a function that wraps an http.Handler
type Middleware func(http.Handler) http.Handler

// 2. Logging Middleware

// LoggingMiddleware logs HTTP requests
func LoggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		// Create a custom response writer to capture status code
		lrw := &loggingResponseWriter{
			ResponseWriter: w,
			statusCode:     http.StatusOK,
		}

		// Call the next handler
		next.ServeHTTP(lrw, r)

		// Log the request
		log.Printf(
			"%s %s %s %d %s",
			r.Method,
			r.RequestURI,
			r.RemoteAddr,
			lrw.statusCode,
			time.Since(start),
		)
	})
}

// loggingResponseWriter wraps http.ResponseWriter to capture status code
type loggingResponseWriter struct {
	http.ResponseWriter
	statusCode int
}

func (lrw *loggingResponseWriter) WriteHeader(code int) {
	lrw.statusCode = code
	lrw.ResponseWriter.WriteHeader(code)
}

// 3. Authentication Middleware

// AuthMiddleware validates authentication tokens
func AuthMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token := r.Header.Get("Authorization")

		if token == "" {
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{
				"error": "Authorization header required",
			})
			return
		}

		// Validate token (simplified)
		if !strings.HasPrefix(token, "Bearer ") {
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{
				"error": "Invalid authorization format",
			})
			return
		}

		actualToken := strings.TrimPrefix(token, "Bearer ")
		if actualToken != "valid-token" {
			w.WriteHeader(http.StatusUnauthorized)
			json.NewEncoder(w).Encode(map[string]string{
				"error": "Invalid token",
			})
			return
		}

		// Add user context
		ctx := context.WithValue(r.Context(), "user", "authenticated-user")
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// 4. CORS Middleware

// CORSMiddleware handles Cross-Origin Resource Sharing
func CORSMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Set CORS headers
		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")
		w.Header().Set("Access-Control-Max-Age", "86400")

		// Handle preflight requests
		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusOK)
			return
		}

		next.ServeHTTP(w, r)
	})
}

// 5. Content Type Middleware

// ContentTypeMiddleware validates and sets content type
func ContentTypeMiddleware(expectedType string) Middleware {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// Check content type for POST/PUT requests
			if r.Method == http.MethodPost || r.Method == http.MethodPut {
				contentType := r.Header.Get("Content-Type")
				if contentType != expectedType {
					w.WriteHeader(http.StatusUnsupportedMediaType)
					json.NewEncoder(w).Encode(map[string]string{
						"error": fmt.Sprintf("Content-Type must be %s", expectedType),
					})
					return
				}
			}

			// Set response content type
			w.Header().Set("Content-Type", expectedType)
			next.ServeHTTP(w, r)
		})
	}
}

// 6. Recovery Middleware

// RecoveryMiddleware recovers from panics
func RecoveryMiddleware(next 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)
				w.WriteHeader(http.StatusInternalServerError)
				json.NewEncoder(w).Encode(map[string]string{
					"error": "Internal Server Error",
				})
			}
		}()

		next.ServeHTTP(w, r)
	})
}

// 7. Request ID Middleware

// RequestIDMiddleware adds unique request ID
func RequestIDMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		requestID := r.Header.Get("X-Request-ID")
		if requestID == "" {
			requestID = fmt.Sprintf("%d", time.Now().UnixNano())
		}

		w.Header().Set("X-Request-ID", requestID)
		ctx := context.WithValue(r.Context(), "requestID", requestID)

		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// 8. Timeout Middleware

// TimeoutMiddleware adds timeout to requests
func TimeoutMiddleware(timeout time.Duration) Middleware {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ctx, cancel := context.WithTimeout(r.Context(), timeout)
			defer cancel()

			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

// 9. Rate Limiting Middleware

// RateLimiter tracks request counts
type RateLimiter struct {
	requests map[string][]time.Time
	limit    int
	window   time.Duration
}

// NewRateLimiter creates a new rate limiter
func NewRateLimiter(limit int, window time.Duration) *RateLimiter {
	rl := &RateLimiter{
		requests: make(map[string][]time.Time),
		limit:    limit,
		window:   window,
	}
	// Start cleanup goroutine
	go rl.cleanup()
	return rl
}

// Allow checks if request is allowed
func (rl *RateLimiter) Allow(ip string) bool {
	now := time.Now()
	rl.requests[ip] = append(rl.requests[ip], now)

	// Remove old requests
	var valid []time.Time
	for _, t := range rl.requests[ip] {
		if now.Sub(t) < rl.window {
			valid = append(valid, t)
		}
	}
	rl.requests[ip] = valid

	return len(rl.requests[ip]) <= rl.limit
}

// cleanup removes old entries
func (rl *RateLimiter) cleanup() {
	ticker := time.NewTicker(time.Minute)
	defer ticker.Stop()

	for range ticker.C {
		now := time.Now()
		for ip, times := range rl.requests {
			var valid []time.Time
			for _, t := range times {
				if now.Sub(t) < rl.window {
					valid = append(valid, t)
				}
			}
			if len(valid) == 0 {
				delete(rl.requests, ip)
			} else {
				rl.requests[ip] = valid
			}
		}
	}
}

// RateLimitMiddleware implements rate limiting
func RateLimitMiddleware(limiter *RateLimiter) Middleware {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ip := r.RemoteAddr

			if !limiter.Allow(ip) {
				w.WriteHeader(http.StatusTooManyRequests)
				json.NewEncoder(w).Encode(map[string]string{
					"error": "Rate limit exceeded",
				})
				return
			}

			next.ServeHTTP(w, r)
		})
	}
}

// 10. Middleware Chain

// Chain chains multiple middleware
func Chain(middlewares ...Middleware) Middleware {
	return func(next http.Handler) http.Handler {
		for i := len(middlewares) - 1; i >= 0; i-- {
			next = middlewares[i](next)
		}
		return next
	}
}

// 11. Example Handlers

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	json.NewEncoder(w).Encode(map[string]string{
		"message": "Welcome Home!",
	})
}

func ProtectedHandler(w http.ResponseWriter, r *http.Request) {
	user := r.Context().Value("user")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"message": "This is a protected endpoint",
		"user":    user,
	})
}

func APIHandler(w http.ResponseWriter, r *http.Request) {
	json.NewEncoder(w).Encode(map[string]string{
		"message": "API endpoint",
	})
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go Middleware Examples ===\n")

	// 1. Setup middlewares
	fmt.Println("--- 1. Available Middleware ---")
	fmt.Println("- LoggingMiddleware")
	fmt.Println("- AuthMiddleware")
	fmt.Println("- CORSMiddleware")
	fmt.Println("- RecoveryMiddleware")
	fmt.Println("- RequestIDMiddleware")

	// 2. Create middleware chain
	fmt.Println("\n--- 2. Middleware Chain ---")
	fmt.Println("Chain order matters:")
	fmt.Println("1. Recovery (outermost)")
	fmt.Println("2. Logging")
	fmt.Println("3. Request ID")
	fmt.Println("4. CORS")
	fmt.Println("5. Authentication")
	fmt.Println("6. Content Type")
	fmt.Println("7. Handler (innermost)")

	// 3. Example router with middleware
	fmt.Println("\n--- 3. Router with Middleware ---")

	// Create handlers
	mux := http.NewServeMux()
	mux.HandleFunc("/", HomeHandler)
	mux.HandleFunc("/protected", ProtectedHandler)
	mux.HandleFunc("/api", APIHandler)

	// Apply middleware chain
	rateLimiter := NewRateLimiter(10, time.Minute)

	handler := Chain(
		RecoveryMiddleware,
		LoggingMiddleware,
		RequestIDMiddleware,
		CORSMiddleware,
		RateLimitMiddleware(rateLimiter),
	)(mux)

	fmt.Printf("Server configured with middleware chain\n")

	// 4. Middleware examples
	fmt.Println("\n--- 4. Middleware Examples ---")

	// Content type middleware
	jsonMiddleware := ContentTypeMiddleware("application/json")
	fmt.Printf("Content-Type middleware created: %T\n", jsonMiddleware)

	// Timeout middleware
	timeoutMiddleware := TimeoutMiddleware(30 * time.Second)
	fmt.Printf("Timeout middleware created: %T\n", timeoutMiddleware)

	// 5. Server configuration
	fmt.Println("\n--- 5. Server Configuration ---")
	fmt.Println("http.ListenAndServe(':8080', handler)")

	// 6. Protected routes example
	fmt.Println("\n--- 6. Protected Routes ---")
	fmt.Println("Public routes: /")
	fmt.Println("Protected routes: /protected (requires auth)")
	fmt.Println("API routes: /api")

	fmt.Println("\n=== All Middleware Examples Completed ===")
}