logo
0
0
WeChat Login
Henry Huang<hhh@rutcode.com>
Refactor: migrate to common.v3 packages and update dependencies

Middlewares Package

This package provides middleware components for both HTTP and gRPC services, organized by functionality. The package is structured into sub-packages to avoid naming conflicts and improve code organization.

Package Structure

middlewares/
├── middlewares.go          # Re-exports all public APIs for backward compatibility
├── httpmw/                 # HTTP middleware (renamed from 'http' to avoid conflict with stdlib)
│   ├── http.go             # CORS, file type checking
│   ├── http_pprof.go       # Performance profiling
│   └── http_prometheus.go  # Prometheus metrics
├── ratelimitmw/            # Rate limiting middleware (wraps utils/ratelimit package)
│   ├── ratelimit.go        # Gin middleware handler
│   ├── ratelimit_helper.go # Helper functions
│   └── ratelimit_http.go   # HTTP handler wrapper
├── circuitbreakermw/       # Circuit breaker middleware (wraps utils/circuitbreaker package)
│   └── circuitbreaker.go  # Gin and HTTP handler wrappers
└── grpcmw/                 # gRPC middleware
    ├── timeout.go          # Timeout interceptor
    ├── error_handler.go    # Error handling interceptor
    ├── logger.go           # Logging interceptor
    ├── compression.go      # Compression interceptor
    └── validation.go       # Request validation interceptor

Note: Tracing utilities have been moved to utils/tracing/ as they are used by both HTTP and gRPC services. IP utilities have been moved to utils/iputil/ as they are general-purpose utilities.

Supported Features

HTTP (Gin)

  • CORS, PProf, Prometheus metrics
  • Timeout, Body Limit, Request Logger
  • Compression (gzip), Validation
  • Authentication/Authorization (JWT, API Key, Basic)
  • Request Deduplication (idempotency key)
  • Swagger/OpenAPI UI and spec serving
  • Response Caching (ETag, Cache-Control, Vary)

gRPC (Interceptors)

  • Timeout, Error Handling, Logging
  • Compression (server-level parameterization)
  • Validation
  • Authentication/Authorization
  • Request Deduplication
  • Response Caching

Package Naming Convention

To avoid conflicts with Go standard library packages, all sub-packages use descriptive suffixes:

  • httpmw - HTTP Middleware (avoids conflict with net/http)
  • grpcmw - gRPC Middleware (unified naming with HTTP middleware)
  • ratelimitmw - Rate Limiting Middleware (wraps utils/ratelimit package)
  • circuitbreakermw - Circuit Breaker Middleware (wraps utils/circuitbreaker package)

Note:

  • Tracing utilities are in utils/tracing/ (used by both HTTP and gRPC)
  • IP utilities are in utils/iputil/ (general-purpose utilities)

Package Relationships

Rate Limiting Architecture

The framework has two rate limiting packages with distinct responsibilities:

1. ratelimit/ (Root Package)

Location: trellis.tech/trellis/common.v3/middleware/ratelimit

Purpose: Core rate limiter implementation

Provides:

  • Limiter interface - Defines rate limiting behavior
  • TokenBucketLimiter - Token bucket algorithm implementation
  • KeyExtractor - Key extraction functions (IP, User ID, Path, etc.)
  • Config - Rate limiter configuration
  • gRPC interceptors - UnaryRateLimitInterceptor, StreamRateLimitInterceptor

Usage: Generic rate limiting that can be used in any context (HTTP, gRPC, etc.)

2. middlewares/ratelimitmw/ (Middleware Package)

Location: trellis.tech/trellis/framework.v0/middlewares/ratelimitmw

Purpose: HTTP middleware wrapper for rate limiting

Provides:

  • RateLimitConfig - Middleware-specific configuration (includes HTTP-specific options)
  • RateLimitHandler - Gin framework middleware
  • RateLimitHTTPHandler - Standard http.Handler wrapper
  • NewRateLimitComponents - Factory function to create rate limiting components

Usage: HTTP/Gin-specific rate limiting middleware

Dependencies: Uses utils/ratelimit package internally

3. middlewares/circuitbreakermw/ (Circuit Breaker Middleware)

Location: trellis.tech/trellis/framework.v0/middlewares/circuitbreakermw

Purpose: HTTP middleware wrapper for circuit breaking

Provides:

  • CircuitBreakerConfig - Middleware-specific configuration
  • CircuitBreakerHandler - Gin framework middleware
  • CircuitBreakerHTTPHandler - Standard http.Handler wrapper
  • NewCircuitBreakerComponents - Factory function to create circuit breaker components

Usage: HTTP/Gin-specific circuit breaker middleware

Dependencies: Uses utils/circuitbreaker package internally

Relationship Diagram

┌─────────────────────────────────┐
│ utils/ratelimit/ (Core Package) │
│   - Limiter interface           │
│   - TokenBucketLimiter          │
│   - KeyExtractor                │
│   - gRPC interceptors            │
└──────────────┬──────────────────┘
               │ uses
               ▼
┌─────────────────────────────────┐
│ middlewares/ratelimitmw/        │
│ - RateLimitConfig               │
│ - RateLimitHandler (Gin)        │
│ - RateLimitHTTPHandler          │
│ - NewRateLimitComponents        │
└─────────────────────────────────┘

┌─────────────────────────────────────┐
│ utils/circuitbreaker/ (Core Package)│
│   - CircuitBreaker                  │
│   - Config                          │
│   - gRPC interceptors               │
└──────────────┬──────────────────────┘
               │ used by
               ▼
┌─────────────────────────────────────┐
│ middlewares/circuitbreakermw/      │
│ - CircuitBreakerConfig              │
│ - CircuitBreakerHandler (Gin)       │
│ - CircuitBreakerHTTPHandler         │
│ - NewCircuitBreakerComponents       │
└─────────────────────────────────────┘

Usage Examples

Using Rate Limiting Middleware

import (
    "trellis.tech/trellis/framework.v0/middlewares/ratelimitmw"
    "trellis.tech/trellis/common.v3/middleware/ratelimit"
)

// Configure rate limiting in service config
rateLimitConfig := &ratelimitmw.RateLimitConfig{
    Enabled:    true,
    Rate:       100,                    // 100 requests
    Period:     "1s",                   // per second
    Burst:      150,                     // allow burst up to 150
    KeyType:    ratelimit.KeyTypeIP, // limit by IP address
    SkipPaths:  []string{"/health", "/metrics"},
    StatusCode: 429,
    Message:    "rate limit exceeded",
}

Using Core Rate Limiter (for gRPC)

import (
    "google.golang.org/grpc"
    "trellis.tech/trellis/common.v3/middleware/ratelimit"
)

// Create rate limiter
config := ratelimit.NewConfig(100, time.Second)
limiter := ratelimit.NewTokenBucketLimiter(config)

// Create key extractor
keyExtractor := ratelimit.NewKeyExtractor(ratelimit.KeyTypeIP, nil)

// Add interceptors
server := grpc.NewServer(
    grpc.UnaryInterceptor(ratelimit.UnaryRateLimitInterceptor(limiter, keyExtractor)),
    grpc.StreamInterceptor(ratelimit.StreamRateLimitInterceptor(limiter, keyExtractor)),
)

Using HTTP Middleware

import (
    "trellis.tech/trellis/framework.v0/middlewares/httpmw"
)

// CORS middleware
cors, err := httpmw.LoadCorsHandler(&httpmw.CorsConfig{
    AllowOrigins: []string{"http://localhost:3000"},
    AllowMethods: []string{"GET", "POST"},
})

// Prometheus metrics
engine.Use(httpmw.RouterPromeHandler("my-service", &httpmw.PromeOpts{}))

// Performance profiling
httpmw.PprofHandler(&httpmw.PprofConfig{Enabled: true}, engine)

Using Circuit Breaker Middleware

import (
    "trellis.tech/trellis/framework.v0/middlewares/circuitbreakermw"
)

// Configure circuit breaker in service config
circuitBreakerConfig := &circuitbreakermw.CircuitBreakerConfig{
    Enabled:            true,
    Name:               "http-service",
    MaxRequests:        1,
    Interval:           "60s",
    Timeout:            "60s",
    ConsecutiveFailures: 5,
    SkipPaths:          []string{"/health", "/metrics"},
    StatusCode:         503,
    Message:            "circuit breaker is open",
}

// The middleware will be automatically applied when CircuitBreakerConfig is set

Using IP Utilities

import (
    "trellis.tech/trellis/framework.v0/utils/iputil"
)

// Get local IP address
ip, err := iputil.GetLocalIp()
if err != nil {
    // Handle error
}

Using Tracing

import (
    "trellis.tech/trellis/common.v3/middleware/tracing"
)

// Get trace ID from context
traceID := tracing.TraceIDFromContext(ctx)

// Tracing is automatically enabled for all HTTP and gRPC services
// See utils/tracing/README.md for details

Using gRPC Middleware

import (
    "google.golang.org/grpc"
    "trellis.tech/trellis/framework.v0/middlewares/grpcmw"
)

// Create gRPC server with interceptors
server := grpc.NewServer(
    grpc.UnaryInterceptor(
        grpcmw.UnaryTimeoutInterceptor(timeoutConfig),
        grpcmw.UnaryErrorHandlerInterceptor(),
        grpcmw.UnaryLoggerInterceptor(loggerConfig),
    ),
)

Backward Compatibility

The middlewares.go file in the root of the middlewares package re-exports all public APIs, allowing existing code to continue using the old import path:

import "trellis.tech/trellis/framework.v0/middlewares"

// These still work:
cfg := &middlewares.RateLimitConfig{...}
middlewares.NewRateLimitComponents(cfg)
middlewares.LoadCorsHandler(...)

However, it's recommended to use the specific sub-packages directly for better clarity:

import "trellis.tech/trellis/framework.v0/middlewares/ratelimitmw"
import "trellis.tech/trellis/framework.v0/middlewares/httpmw"

Key Types for Rate Limiting

  • KeyTypeIP - Rate limit by client IP address
  • KeyTypeUserID - Rate limit by user ID (from context)
  • KeyTypePath - Rate limit by request path
  • KeyTypeIPPath - Rate limit by IP + path combination
  • KeyTypeUserPath - Rate limit by user ID + path combination
  • KeyTypeCustom - Use custom extractor function

Testing

All sub-packages include comprehensive test coverage:

# Run tests for all middlewares
go test ./middlewares/...

# Run tests for specific sub-package
go test ./middlewares/ratelimitmw
go test ./middlewares/circuitbreakermw
go test ./middlewares/httpmw
go test ./middlewares/grpcmw

Migration Guide

If you're migrating from the old structure:

  1. Import paths: Update imports from middlewares to specific sub-packages

    • middlewares.RateLimitConfigratelimitmw.RateLimitConfig
    • middlewares.LoadCorsHandlerhttpmw.LoadCorsHandler
  2. Package aliases: You may need to add aliases to avoid conflicts

    import (
        ratelimitmw "trellis.tech/trellis/framework.v0/middlewares/ratelimitmw"
        "trellis.tech/trellis/common.v3/middleware/ratelimit"
    )
    
  3. Type references: Update type references in your code

    • *middlewares.RateLimitConfig*ratelimitmw.RateLimitConfig
    • *middlewares.CorsConfig*httpmw.CorsConfig