Middleware
Use built-in and custom middleware for logging, request IDs, real client IP detection, CORS, compression, content validation, caching, and request normalization.
Middleware allows you to run logic before or after a route handler.
It is commonly used for:
- request logging
- request IDs
- real client IP detection
- CORS
- compression
- cache headers
- content validation
- rate limiting
- custom application logic
Middleware uses the standard router middleware signature:
type Middleware func(router.HandlerFunc) router.HandlerFuncRegistering Middleware
Register global middleware with r.Use.
r.Use(router.Logger())
r.Use(router.RequestID())
r.Use(router.RealIP())Global middleware applies to all routes registered on the router.
Built-in Middleware Overview
| Middleware / Helper | Type | Description |
|---|---|---|
Use | Registration | Registers global middleware on the router |
With | Registration | Creates a scoped middleware group for selected routes |
Group.Use | Registration | Registers middleware only for a route group |
UseDefaults | Preset | Registers GetHead, RequestID, RealIP, and NoCache |
Logger | Middleware | Logs request method, host, path, query, request ID, and duration |
RequestID | Middleware | Adds a request ID to the request context and response header |
RequestIDWithGenerator | Middleware | Adds a request ID using a custom ID generator |
RequestIDFromContext | Helper | Reads the request ID from context.Context |
RealIP | Middleware | Resolves the real client IP and stores it in X-Real-IP |
SetTrustedProxies | Helper | Configures trusted proxy CIDR ranges for real IP detection |
ClientIP | Helper | Resolves the client IP from trusted proxy headers or remote address |
CORS | Middleware | Handles Cross-Origin Resource Sharing and preflight requests |
NoCache | Middleware | Adds headers that prevent browser and proxy caching |
Compress | Middleware | Applies gzip compression for selected content types |
DefaultCompress | Middleware | Applies gzip compression for common text and JSON content types |
AllowContentType | Middleware | Restricts requests based on the Content-Type header |
ContentCharset | Middleware | Validates accepted request character sets |
GetHead | Middleware | Treats HEAD requests as GET requests for handlers |
CleanPath | Middleware | Normalizes the request path before passing it to the handler |
RateLimit | Middleware | Limits request frequency per client and route |
Example
package main
import (
"compress/gzip"
"log/slog"
"net/http"
"os"
"github.com/netlifeguru/router"
)
func main() {
r := router.New()
r.Use(router.Logger())
r.Use(router.RequestID())
if err := router.SetTrustedProxies([]string{"10.0.0.0/8"}); err != nil {
slog.Error("failed to set trusted proxies", "error", err)
}
r.Use(router.RealIP())
r.Use(router.GetHead())
r.Use(router.CleanPath())
r.Use(router.CORS(router.CORSOptions{
AllowedOrigins: []string{"https://*", "http://*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: false,
MaxAge: 300,
}))
r.Use(router.NoCache())
r.Use(router.Compress(
gzip.DefaultCompression,
"text/html",
"text/plain",
"text/css",
"application/javascript",
"text/javascript",
"application/json",
))
r.Use(router.AllowContentType("application/json", "text/xml"))
r.Use(router.ContentCharset("UTF-8", "Latin-1", ""))
r.Use(func(next router.HandlerFunc) router.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
next(w, req, ctx)
}
})
r.GET("/", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`Hello World`))
})
if err := r.ListenAndServe(":8000"); err != nil {
slog.Error("failed to start server", "error", err)
os.Exit(1)
}
}Default Middleware
Use UseDefaults to register a small default middleware set.
r.UseDefaults()This registers:
GetHeadRequestIDRealIPNoCache
Use this when you want sensible defaults without configuring each middleware manually.
Custom Middleware
Custom middleware can wrap any route handler.
r.Use(func(next router.HandlerFunc) router.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
// before handler
next(w, req, ctx)
// after handler
}
})This is useful for authentication, authorization, tracing, request-scoped dependencies, custom headers, and application-specific behavior.
Notes
Middleware order matters.
Middleware is executed in the order it is registered, while handlers are wrapped internally so each middleware can run logic before and after the next handler.
For route-group specific middleware, use route groups and Group.Use.