middleware

package
v0.0.0-...-497eae4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 13, 2026 License: MIT Imports: 9 Imported by: 0

README

Middleware Package

HTTP middleware utilities for Go applications. This package provides common middleware patterns for building robust HTTP servers.

Features

  • RequestID: Injects unique request IDs for request tracing
  • Logging: Structured logging of HTTP requests/responses
  • Recovery: Panic recovery to prevent server crashes
  • CORS: Cross-Origin Resource Sharing support
  • Timeout: Request timeout enforcement
  • Chain: Compose multiple middlewares together

Installation

go get github.com/ArgonautPath/go-kit/pkg/middleware

Usage with Standard net/http

import (
    "net/http"
    "github.com/ArgonautPath/go-kit/pkg/middleware"
    "github.com/ArgonautPath/go-kit/pkg/logger"
)

// Create logger
log, _ := logger.New(logger.Config{...})

// Create middleware chain
chain := middleware.Chain(
    middleware.RequestID(),
    middleware.Recovery(),
    middleware.Logging(log),
    middleware.CORS(middleware.CORSConfig{
        AllowedOrigins: []string{"https://example.com"},
    }),
    middleware.Timeout(30 * time.Second),
)

// Apply to handler
handler := chain(yourHandler)
http.ListenAndServe(":8080", handler)

Usage with Gin Framework

The middleware package includes Gin adapters to use with the Gin framework.

Note: To use Gin adapters, you need to add Gin as a dependency:

go get github.com/gin-gonic/gin
Using GinAdapter
import (
    "github.com/gin-gonic/gin"
    "github.com/ArgonautPath/go-kit/pkg/middleware"
    "github.com/ArgonautPath/go-kit/pkg/logger"
)

r := gin.Default()

// Use GinAdapter to convert standard middleware to Gin middleware
r.Use(middleware.GinAdapter(middleware.RequestID()))
r.Use(middleware.GinAdapter(middleware.Recovery()))
r.Use(middleware.GinAdapter(middleware.Logging(log)))
Using Convenience Functions
r := gin.Default()

// Convenience functions for each middleware
r.Use(middleware.GinRequestID())
r.Use(middleware.GinRecovery())
r.Use(middleware.GinLogging(log))
r.Use(middleware.GinCORS(middleware.CORSConfig{
    AllowedOrigins: []string{"https://example.com"},
}))
r.Use(middleware.GinTimeout(30 * time.Second))
Complete Gin Example
package main

import (
    "net/http"
    "time"
    
    "github.com/gin-gonic/gin"
    "github.com/ArgonautPath/go-kit/pkg/logger"
    "github.com/ArgonautPath/go-kit/pkg/middleware"
)

func main() {
    log, _ := logger.New(logger.Config{...})
    
    r := gin.Default()
    
    // Apply middlewares
    r.Use(middleware.GinRequestID())
    r.Use(middleware.GinRecovery())
    r.Use(middleware.GinLogging(log))
    r.Use(middleware.GinCORS(middleware.CORSConfig{
        AllowedOrigins: []string{"*"},
    }))
    
    // Routes
    r.GET("/", func(c *gin.Context) {
        requestID := middleware.GetRequestID(c.Request.Context())
        c.JSON(http.StatusOK, gin.H{
            "request_id": requestID,
            "message": "Hello, World!",
        })
    })
    
    r.Run(":8080")
}

Building Without Gin

If you don't use Gin, you can build the package without Gin support using the build tag:

go build -tags=no_gin ./pkg/middleware/...

This excludes the Gin adapter code from compilation.

Middleware Details

RequestID

Injects a unique request ID into each request for tracing.

middleware.RequestID(
    middleware.WithRequestIDHeader("X-Request-ID"),
    middleware.WithRequestIDResponse(true),
)
Logging

Logs HTTP requests and responses with structured logging.

middleware.Logging(log,
    middleware.WithSkipPaths("/health", "/metrics"),
    middleware.WithSkipStatusCodes(200),
)
Recovery

Recovers from panics and prevents server crashes.

middleware.Recovery(
    middleware.WithRecoveryPrintStack(false),
    middleware.WithRecoveryHandler(customHandler),
)
CORS

Handles Cross-Origin Resource Sharing headers.

middleware.CORS(middleware.CORSConfig{
    AllowedOrigins: []string{"https://example.com"},
    AllowedMethods: []string{"GET", "POST"},
    AllowedHeaders: []string{"Content-Type"},
    AllowCredentials: true,
})
Timeout

Enforces request timeouts.

middleware.Timeout(30 * time.Second,
    middleware.WithTimeoutMessage("Request timeout"),
    middleware.WithTimeoutStatusCode(http.StatusRequestTimeout),
)

See Also

Documentation

Index

Constants

View Source
const (
	// RequestIDHeader is the standard header name for request IDs.
	RequestIDHeader = "X-Request-ID"
	// RequestIDContextKey is the context key for storing request IDs.
	RequestIDContextKey contextKey = "request_id"
)

Variables

This section is empty.

Functions

func Apply

func Apply(m Middleware, handler http.Handler) http.Handler

Apply applies a middleware to an http.Handler.

func ApplyFunc

func ApplyFunc(m Middleware, handler HandlerFunc) http.Handler

ApplyFunc applies a middleware to an http.HandlerFunc.

func GetRequestID

func GetRequestID(ctx context.Context) string

GetRequestID retrieves the request ID from the context. Returns an empty string if no request ID is found.

func GinAdapter

func GinAdapter(m Middleware) gin.HandlerFunc

GinAdapter adapts a standard http.Handler middleware to work with Gin. This allows you to use go-kit middleware with Gin framework.

Gin's middleware uses gin.HandlerFunc (func(*gin.Context)), while our middleware uses http.Handler. This adapter bridges the gap.

Example:

import "github.com/ArgonautPath/go-kit/pkg/middleware"

r := gin.Default()
r.Use(middleware.GinAdapter(middleware.RequestID()))
r.Use(middleware.GinAdapter(middleware.Recovery()))
r.Use(middleware.GinAdapter(middleware.Logging(logger)))

func GinCORS

func GinCORS(cfg CORSConfig) gin.HandlerFunc

GinCORS is a convenience function that returns a Gin middleware for CORS. It's equivalent to: GinAdapter(CORS(cfg))

Example:

r := gin.Default()
r.Use(middleware.GinCORS(middleware.CORSConfig{
	AllowedOrigins: []string{"https://example.com"},
	AllowedMethods: []string{"GET", "POST"},
}))

func GinLogging

func GinLogging(l logger.Logger, opts ...LoggingOption) gin.HandlerFunc

GinLogging is a convenience function that returns a Gin middleware for logging. It requires a logger from the logger package.

Example:

import (
	"github.com/ArgonautPath/go-kit/pkg/logger"
	"github.com/ArgonautPath/go-kit/pkg/middleware"
)

log, _ := logger.New(logger.Config{...})
r := gin.Default()
r.Use(middleware.GinLogging(log))
r.Use(middleware.GinLogging(log, middleware.WithSkipPaths("/health")))

func GinRecovery

func GinRecovery(opts ...RecoveryOption) gin.HandlerFunc

GinRecovery is a convenience function that returns a Gin middleware for recovery. It's equivalent to: GinAdapter(Recovery())

Example:

r := gin.Default()
r.Use(middleware.GinRecovery())
r.Use(middleware.GinRecovery(middleware.WithRecoveryPrintStack(true)))

func GinRequestID

func GinRequestID(opts ...RequestIDOption) gin.HandlerFunc

GinRequestID is a convenience function that returns a Gin middleware for request ID. It's equivalent to: GinAdapter(RequestID())

Example:

r := gin.Default()
r.Use(middleware.GinRequestID())
r.Use(middleware.GinRequestID(middleware.WithRequestIDHeader("X-Custom-ID")))

func GinTimeout

func GinTimeout(timeout time.Duration, opts ...TimeoutOption) gin.HandlerFunc

GinTimeout is a convenience function that returns a Gin middleware for timeout. It's equivalent to: GinAdapter(Timeout(timeout, opts...))

Example:

r := gin.Default()
r.Use(middleware.GinTimeout(30 * time.Second))
r.Use(middleware.GinTimeout(30*time.Second, middleware.WithTimeoutMessage("Too slow")))

func ToGinMiddleware

func ToGinMiddleware(m Middleware) gin.HandlerFunc

ToGinMiddleware converts a standard middleware to a Gin middleware. This is an alias for GinAdapter for better readability.

Types

type CORSConfig

type CORSConfig struct {
	// AllowedOrigins is a list of allowed origins. Use "*" to allow all origins.
	AllowedOrigins []string
	// AllowedMethods is a list of allowed HTTP methods.
	AllowedMethods []string
	// AllowedHeaders is a list of allowed headers.
	AllowedHeaders []string
	// ExposedHeaders is a list of headers that can be exposed to the client.
	ExposedHeaders []string
	// AllowCredentials indicates whether credentials can be included in requests.
	AllowCredentials bool
	// MaxAge is the maximum age for preflight requests in seconds.
	MaxAge int
}

CORSConfig holds configuration for the CORS middleware.

type HandlerFunc

type HandlerFunc func(http.ResponseWriter, *http.Request)

HandlerFunc is a function type that matches http.HandlerFunc.

type LoggingConfig

type LoggingConfig struct {
	// Logger is the logger instance to use. If nil, logging is skipped.
	Logger logger.Logger
	// LogRequestHeaders logs request headers.
	LogRequestHeaders bool
	// LogResponseHeaders logs response headers.
	LogResponseHeaders bool
	// LogRequestBody logs request body (use with caution for large bodies).
	LogRequestBody bool
	// LogResponseBody logs response body (use with caution for large bodies).
	LogResponseBody bool
	// SkipPaths is a list of paths to skip logging.
	SkipPaths []string
	// SkipStatusCodes is a list of HTTP status codes to skip logging.
	SkipStatusCodes []int
}

LoggingConfig holds configuration for the Logging middleware.

type LoggingOption

type LoggingOption func(*LoggingConfig)

LoggingOption is a functional option for Logging middleware.

func WithLogRequestBody

func WithLogRequestBody(enabled bool) LoggingOption

WithLogRequestBody enables logging of request body.

func WithLogRequestHeaders

func WithLogRequestHeaders(enabled bool) LoggingOption

WithLogRequestHeaders enables logging of request headers.

func WithLogResponseBody

func WithLogResponseBody(enabled bool) LoggingOption

WithLogResponseBody enables logging of response body.

func WithLogResponseHeaders

func WithLogResponseHeaders(enabled bool) LoggingOption

WithLogResponseHeaders enables logging of response headers.

func WithSkipPaths

func WithSkipPaths(paths ...string) LoggingOption

WithSkipPaths sets paths to skip logging.

func WithSkipStatusCodes

func WithSkipStatusCodes(codes ...int) LoggingOption

WithSkipStatusCodes sets status codes to skip logging.

type Middleware

type Middleware func(http.Handler) http.Handler

Middleware is a function that wraps an HTTP handler. It receives the next handler in the chain and returns a new handler.

func CORS

func CORS(cfg CORSConfig) Middleware

CORS handles Cross-Origin Resource Sharing (CORS) headers. It supports preflight OPTIONS requests and adds appropriate CORS headers to all responses.

Example:

mux := http.NewServeMux()
handler := CORS(CORSConfig{
	AllowedOrigins: []string{"https://example.com"},
	AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
	AllowedHeaders: []string{"Content-Type", "Authorization"},
})(mux)

func Chain

func Chain(middlewares ...Middleware) Middleware

Chain chains multiple middlewares together. Middlewares are executed in the order they are provided. The first middleware in the slice is the outermost (executed first), and the last middleware is the innermost (executed last).

Example:

chain := Chain(
	RequestID(),
	Recovery(),
	Logging(logger),
)
handler := chain(finalHandler)

func Logging

func Logging(l logger.Logger, opts ...LoggingOption) Middleware

Logging logs HTTP requests and responses using the provided logger. It logs request method, path, status code, duration, and optionally headers and bodies.

Example:

log, _ := logger.New(logger.Config{...})
mux := http.NewServeMux()
handler := Logging(log)(mux)

func Recovery

func Recovery(opts ...RecoveryOption) Middleware

Recovery recovers from panics and returns a 500 Internal Server Error. It prevents the server from crashing and optionally logs the panic.

Example:

mux := http.NewServeMux()
handler := Recovery()(mux)

func RequestID

func RequestID(opts ...RequestIDOption) Middleware

RequestID injects a request ID into the request context and optionally adds it to response headers. The request ID is extracted from the request header if present, otherwise a new one is generated.

The request ID can be retrieved from the context using GetRequestID.

Example:

mux := http.NewServeMux()
mux.HandleFunc("/", handler)
handler := RequestID()(mux)
http.ListenAndServe(":8080", handler)

func Timeout

func Timeout(timeout time.Duration, opts ...TimeoutOption) Middleware

Timeout adds a timeout to request handling. If the handler takes longer than the specified timeout, the request is cancelled and an error response is returned.

Example:

mux := http.NewServeMux()
handler := Timeout(30 * time.Second)(mux)

type RecoveryConfig

type RecoveryConfig struct {
	// Handler is called when a panic occurs. If nil, a default handler is used.
	Handler func(http.ResponseWriter, *http.Request, interface{})
	// PrintStack prints the stack trace to the response.
	PrintStack bool
	// StackSize limits the size of the printed stack trace.
	StackSize int
}

RecoveryConfig holds configuration for the Recovery middleware.

type RecoveryOption

type RecoveryOption func(*RecoveryConfig)

RecoveryOption is a functional option for Recovery middleware.

func WithRecoveryHandler

func WithRecoveryHandler(handler func(http.ResponseWriter, *http.Request, interface{})) RecoveryOption

WithRecoveryHandler sets a custom panic handler.

func WithRecoveryPrintStack

func WithRecoveryPrintStack(enabled bool) RecoveryOption

WithRecoveryPrintStack enables printing the stack trace in the response.

func WithRecoveryStackSize

func WithRecoveryStackSize(size int) RecoveryOption

WithRecoveryStackSize sets the maximum stack trace size to print.

type RequestIDConfig

type RequestIDConfig struct {
	// HeaderName is the HTTP header name to use for request IDs.
	// Default: "X-Request-ID"
	HeaderName string
	// GenerateID is a function to generate request IDs.
	// If nil, uses UUID v4.
	GenerateID func() string
	// AddToResponse adds the request ID to the response headers.
	// Default: true
	AddToResponse bool
}

RequestIDConfig holds configuration for the RequestID middleware.

type RequestIDOption

type RequestIDOption func(*RequestIDConfig)

RequestIDOption is a functional option for RequestID middleware.

func WithRequestIDGenerator

func WithRequestIDGenerator(generator func() string) RequestIDOption

WithRequestIDGenerator sets a custom request ID generator.

func WithRequestIDHeader

func WithRequestIDHeader(headerName string) RequestIDOption

WithRequestIDHeader sets the header name for request IDs.

func WithRequestIDResponse

func WithRequestIDResponse(addToResponse bool) RequestIDOption

WithRequestIDResponse sets whether to add request ID to response headers.

type TimeoutConfig

type TimeoutConfig struct {
	// Timeout is the maximum duration for request handling.
	Timeout time.Duration
	// Message is the error message to return on timeout.
	Message string
	// StatusCode is the HTTP status code to return on timeout.
	StatusCode int
}

TimeoutConfig holds configuration for the Timeout middleware.

type TimeoutOption

type TimeoutOption func(*TimeoutConfig)

TimeoutOption is a functional option for Timeout middleware.

func WithTimeoutMessage

func WithTimeoutMessage(message string) TimeoutOption

WithTimeoutMessage sets the error message for timeout responses.

func WithTimeoutStatusCode

func WithTimeoutStatusCode(code int) TimeoutOption

WithTimeoutStatusCode sets the HTTP status code for timeout responses.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL