middleware

package
v1.15.1 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2025 License: MIT Imports: 23 Imported by: 0

README

middleware

Common gin middleware libraries, including:


Example of use

Logging middleware

You can set the maximum length for printing, add a request id field, ignore print path, customize zap log.

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
)

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    // Print input parameters and return results
    // Case 1: default
    {
        r.Use(middleware.Logging()
    }
    // Case 2: custom
    {
        r.Use(middleware.Logging(
            middleware.WithLog(logger.Get()))
            middleware.WithMaxLen(400),
            middleware.WithRequestIDFromHeader(),
            //middleware.WithRequestIDFromContext(),
            //middleware.WithIgnoreRoutes("/hello"),
        ))
    }

    /*******************************************
    TIP: You can use middleware.SimpleLog instead of
           middleware.Logging, it only prints return results
    *******************************************/

    // ......
    return r
}

Allow cross-domain requests middleware

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
)

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    r.Use(middleware.Cors())

    // ......
    return r
}

Rate limiter middleware

Adaptive flow limitation based on hardware resources.

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
)

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    // Case 1: default
    r.Use(middleware.RateLimit())

    // Case 2: custom
    r.Use(middleware.RateLimit(
        middleware.WithWindow(time.Second*10),
        middleware.WithBucket(1000),
        middleware.WithCPUThreshold(100),
        middleware.WithCPUQuota(0.5),
    ))

    // ......
    return r
}

Circuit Breaker middleware

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
)

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    r.Use(middleware.CircuitBreaker(
        //middleware.WithValidCode(http.StatusRequestTimeout), // add error code 408 for circuit breaker
        //middleware.WithDegradeHandler(handler), // add custom degrade handler
        //middleware.WithBreakerOption(
            //circuitbreaker.WithSuccess(75),           // default 60
            //circuitbreaker.WithRequest(200),          // default 100
            //circuitbreaker.WithBucket(20),            // default 10
            //circuitbreaker.WithWindow(time.Second*5), // default 3s
        //),
    ))

    // ......
    return r
}

JWT authorization middleware

There are two usage examples available:

  1. Example One: This example adopts a highly abstracted design, making it simpler and more convenient to use. Click to view the example at pkg/gin/middleware/auth. Requires sponge version v1.13.2+.

  2. Example Two: This example offers greater flexibility and is suitable for scenarios requiring custom implementations. The example code is as follows:

    package main
    
    import (
        "time"
        "github.com/gin-gonic/gin"
        "github.com/go-dev-frame/sponge/pkg/gin/middleware"
        "github.com/go-dev-frame/sponge/pkg/gin/response"
        "github.com/go-dev-frame/sponge/pkg/jwt"
    )
    
    func main() {
        r := gin.Default()
    
        g := r.Group("/api/v1")
    
        // Case 1: default jwt options, signKey, signMethod(HS256), expiry time(24 hour)
        {
            r.POST("/auth/login", LoginDefault)
            g.Use(middleware.Auth())
            //g.Use(middleware.Auth(middleware.WithExtraVerify(extraVerifyFn))) // add extra verify function
        }
    
        // Case 2: custom jwt options, signKey, signMethod(HS512), expiry time(48 hour), fields, claims
        {
            r.POST("/auth/login", LoginCustom)
            signKey := []byte("your-sign-key")
            g.Use(middleware.Auth(middleware.WithSignKey(signKey)))
            //g.Use(middleware.Auth(middleware.WithSignKey(signKey), middleware.WithExtraVerify(extraVerifyFn))) // add extra verify function
        }
    
        g.GET("/user/:id", GetByID)
        //g.PUT("/user/:id", Create)
        //g.DELETE("/user/:id", DeleteByID)
    
        r.Run(":8080")
    }
    
    func customGenerateToken(uid string, fields map[string]interface{}) (string, error) {
        _, token, err := jwt.GenerateToken(
            uid,
            jwt.WithGenerateTokenSignKey([]byte("custom-sign-key")),
            jwt.WithGenerateTokenSignMethod(jwt.HS512),
            jwt.WithGenerateTokenFields(fields),
            jwt.WithGenerateTokenClaims([]jwt.RegisteredClaimsOption{
                jwt.WithExpires(time.Hour * 48),
                //jwt.WithIssuedAt(now),
                // jwt.WithSubject("123"),
                // jwt.WithIssuer("https://middleware.example.com"),
                // jwt.WithAudience("https://api.example.com"),
                // jwt.WithNotBefore(now),
                // jwt.WithJwtID("abc1234xxx"),
            }...),
        )
    
        return token, err
    }
    
    func LoginDefault(c *gin.Context) {
        // ......
    
        _, token, err := jwt.GenerateToken("100")
    
        response.Success(c, token)
    }
    
    func LoginCustom(c *gin.Context) {
        // ......
    
        uid := "100"
        fields := map[string]interface{}{
            "name":   "bob",
            "age":    10,
            "is_vip": true,
        }
    
        token, err := customGenerateToken(uid, fields)
    
        response.Success(c, token)
    }
    
    func GetByID(c *gin.Context) {
        uid := c.Param("id")
    
        // if necessary, claims can be got from gin context.
        claims, ok := middleware.GetClaims(c)
        //uid := claims.UID
        //name, _ := claims.GetString("name")
        //age, _ := claims.GetInt("age")
        //isVip, _ := claims.GetBool("is_vip")
    
        response.Success(c, gin.H{"id": uid})
    }
    
    func extraVerifyFn(claims *jwt.Claims, c *gin.Context) error {
        // check if token is about to expire (less than 10 minutes remaining)
        if time.Now().Unix()-claims.ExpiresAt.Unix() < int64(time.Minute*10) {
            token, err := claims.NewToken(time.Hour*24, jwt.HS512, []byte("your-sign-key")) // same signature as jwt.GenerateToken
            if err != nil {
                return err
            }
            c.Header("X-Renewed-Token", token)
        }
    
        // judge whether the user is disabled, query whether jwt id exists from the blacklist
        //if CheckBlackList(uid, claims.ID) {
        //    return errors.New("user is disabled")
        //}
    
        return nil
    }
    

Tracing middleware

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
    "github.com/go-dev-frame/sponge/pkg/tracer"
)

func InitTrace(serviceName string) {
    exporter, err := tracer.NewJaegerAgentExporter("192.168.3.37", "6831")
    if err != nil {
        panic(err)
    }

    resource := tracer.NewResource(
        tracer.WithServiceName(serviceName),
        tracer.WithEnvironment("dev"),
        tracer.WithServiceVersion("demo"),
    )

    tracer.Init(exporter, resource) // collect all by default
}

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    r.Use(middleware.Tracing("your-service-name"))

    // ......
    return r
}

// if necessary, you can create a span in the program
func CreateSpanDemo(serviceName string, spanName string, ctx context.Context) {
    _, span := otel.Tracer(serviceName).Start(
        ctx, spanName,
        trace.WithAttributes(attribute.String(spanName, time.Now().String())),
    )
    defer span.End()

    // ......
}

Metrics middleware

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware/metrics"
)

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    r.Use(metrics.Metrics(r,
        //metrics.WithMetricsPath("/demo/metrics"), // default is /metrics
        metrics.WithIgnoreStatusCodes(http.StatusNotFound), // ignore status codes
        //metrics.WithIgnoreRequestMethods(http.MethodHead),  // ignore request methods
        //metrics.WithIgnoreRequestPaths("/ping", "/health"), // ignore request paths
    ))

    // ......
    return r

Request id middleware

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
)

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    // Case 1: default request id
    {
        r.Use(middleware.RequestID())
    }
    // Case 2: custom request id key
    {
        //r.User(middleware.RequestID(
        //    middleware.WithContextRequestIDKey("your ctx request id key"), // default is request_id
        //    middleware.WithHeaderRequestIDKey("your header request id key"), // default is X-Request-Id
        //))
        // If you change the ContextRequestIDKey, you have to set the same key name if you want to print the request id in the mysql logs as well.
        // example:
        //     db, err := mysql.Init(dsn,mysql.WithLogRequestIDKey("your ctx request id key"))  // print request_id
    }

    // ......
    return r
}

Timeout middleware

import (
    "github.com/gin-gonic/gin"
    "github.com/go-dev-frame/sponge/pkg/gin/middleware"
)

func NewRouter() *gin.Engine {
    r := gin.Default()
    // ......

    // Case 1: global set timeout
    {
        r.Use(middleware.Timeout(time.Second*5))
    }
    // Case 2: set timeout for specifyed router
    {
        r.GET("/userExample/:id", middleware.Timeout(time.Second*3), GetByID)
    }
    // Note: If timeout is set both globally and in the router, the minimum timeout prevails

    // ......
    return r
}

func GetByID(c *gin.Context) {
    // do something
}

Documentation

Overview

Package middleware is gin middleware plugin.

Index

Constants

View Source
const HeaderAuthorizationKey = "Authorization"

HeaderAuthorizationKey http header authorization key, value is "Bearer token"

Variables

View Source
var (
	// ContextRequestIDKey request id for context
	ContextRequestIDKey = "request_id"

	// HeaderXRequestIDKey header request id key
	HeaderXRequestIDKey = "X-Request-Id"
)
View Source
var ErrLimitExceed = rl.ErrLimitExceed

ErrLimitExceed is returned when the rate limiter is triggered and the request is rejected due to limit exceeded.

ErrNotAllowed error not allowed.

View Source
var RequestHeaderKey = "request_header_key"

RequestHeaderKey request header key

RequestIDKey request_id

View Source
var WithVerify = WithExtraVerify

WithVerify alias of WithExtraVerify

Functions

func AdaptCtx

func AdaptCtx(ctx context.Context) (*gin.Context, context.Context)

AdaptCtx adapt context, if ctx is gin.Context, return gin.Context and context of the transformation

func Auth

func Auth(opts ...AuthOption) gin.HandlerFunc

Auth authorization middleware, support custom extra verify.

func CircuitBreaker

func CircuitBreaker(opts ...CircuitBreakerOption) gin.HandlerFunc

CircuitBreaker a circuit breaker middleware

func Cors

func Cors() gin.HandlerFunc

Cors cross domain

func CtxRequestID

func CtxRequestID(ctx context.Context) string

CtxRequestID get request id from context.Context

func CtxRequestIDField

func CtxRequestIDField(ctx context.Context) zap.Field

CtxRequestIDField get request id field from context.Context

func GCtxRequestID

func GCtxRequestID(c *gin.Context) string

GCtxRequestID get request id from gin.Context

func GCtxRequestIDField

func GCtxRequestIDField(c *gin.Context) zap.Field

GCtxRequestIDField get request id field from gin.Context

func GetClaims added in v1.13.0

func GetClaims(c *gin.Context) (*jwt.Claims, bool)

GetClaims get jwt claims from gin context.

func GetFromCtx

func GetFromCtx(ctx context.Context, key string) interface{}

GetFromCtx get value from context

func GetFromHeader

func GetFromHeader(ctx context.Context, key string) string

GetFromHeader get value from header

func GetFromHeaders

func GetFromHeaders(ctx context.Context, key string) []string

GetFromHeaders get values from header

func HeaderRequestID

func HeaderRequestID(c *gin.Context) string

HeaderRequestID get request id from the header

func HeaderRequestIDField

func HeaderRequestIDField(c *gin.Context) zap.Field

HeaderRequestIDField get request id field from header

func Logging

func Logging(opts ...Option) gin.HandlerFunc

Logging print request and response info

func RailsCookieAuthMiddleware added in v1.14.5

func RailsCookieAuthMiddleware(secretKeyBase string, cookieName string) gin.HandlerFunc

RailsCookieAuthMiddleware validates and decrypts a Rails encrypted cookie, attaches the session payload to context under key "rails_session".

func RateLimit

func RateLimit(opts ...RateLimitOption) gin.HandlerFunc

RateLimit an adaptive rate limiter middleware

func RequestID

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

RequestID is an interceptor that injects a 'request id' into the context and request/response header of each request.

func SimpleLog

func SimpleLog(opts ...Option) gin.HandlerFunc

SimpleLog print response info

func Timeout

func Timeout(d time.Duration) gin.HandlerFunc

Timeout request time out

func Tracing

func Tracing(serviceName string, opts ...TraceOption) gin.HandlerFunc

Tracing returns interceptor that will trace incoming requests. The service parameter should describe the name of the (virtual) server handling the request.

func WrapCtx

func WrapCtx(c *gin.Context) context.Context

WrapCtx wrap context, put the Keys and Header of gin.Context into context

Types

type AuthOption added in v1.12.2

type AuthOption func(*authOptions)

AuthOption set the auth options.

func WithExtraVerify added in v1.13.0

func WithExtraVerify(fn ExtraVerifyFn) AuthOption

WithExtraVerify set extra verify function

func WithReturnErrReason added in v1.13.0

func WithReturnErrReason() AuthOption

WithReturnErrReason set return error reason

func WithSignKey added in v1.13.0

func WithSignKey(key []byte) AuthOption

WithSignKey set jwt sign key

type CircuitBreakerOption

type CircuitBreakerOption func(*circuitBreakerOptions)

CircuitBreakerOption set the circuit breaker circuitBreakerOptions.

func WithBreakerOption added in v1.14.3

func WithBreakerOption(opts ...circuitbreaker.Option) CircuitBreakerOption

WithBreakerOption set the circuit breaker options.

func WithDegradeHandler

func WithDegradeHandler(handler func(c *gin.Context)) CircuitBreakerOption

WithDegradeHandler set degrade handler function

func WithGroup

func WithGroup(g *group.Group) CircuitBreakerOption

WithGroup with circuit breaker group. Deprecated: use WithBreakerOption instead

func WithValidCode

func WithValidCode(code ...int) CircuitBreakerOption

WithValidCode http code to mark failed

type CtxKeyString

type CtxKeyString string

CtxKeyString for context.WithValue key type

type ExtraVerifyFn added in v1.13.0

type ExtraVerifyFn = func(claims *jwt.Claims, c *gin.Context) error

ExtraVerifyFn extra verify function

type Option

type Option func(*options)

Option set the gin logger options.

func WithIgnoreRoutes

func WithIgnoreRoutes(routes ...string) Option

WithIgnoreRoutes no logger content routes

func WithLog

func WithLog(log *zap.Logger) Option

WithLog set log

func WithMaxLen

func WithMaxLen(maxLen int) Option

WithMaxLen logger content max length

func WithPrintErrorByCodes added in v1.13.0

func WithPrintErrorByCodes(code ...int) Option

WithPrintErrorByCodes set print error by specified codes

func WithRequestIDFromContext

func WithRequestIDFromContext() Option

WithRequestIDFromContext name is field in context, default value is request_id

func WithRequestIDFromHeader

func WithRequestIDFromHeader() Option

WithRequestIDFromHeader name is field in header, default value is X-Request-Id

type RateLimitOption

type RateLimitOption func(*rateLimitOptions)

RateLimitOption set the rate limits rateLimitOptions.

func WithBucket

func WithBucket(b int) RateLimitOption

WithBucket with bucket size.

func WithCPUQuota

func WithCPUQuota(quota float64) RateLimitOption

WithCPUQuota with real cpu quota(if it can not collect from process correct);

func WithCPUThreshold

func WithCPUThreshold(threshold int64) RateLimitOption

WithCPUThreshold with cpu threshold

func WithWindow

func WithWindow(d time.Duration) RateLimitOption

WithWindow with window size.

type RequestIDOption

type RequestIDOption func(*requestIDOptions)

RequestIDOption set the request id options.

func WithContextRequestIDKey

func WithContextRequestIDKey(key string) RequestIDOption

WithContextRequestIDKey set context request id key, minimum length of 4

func WithHeaderRequestIDKey

func WithHeaderRequestIDKey(key string) RequestIDOption

WithHeaderRequestIDKey set header request id key, minimum length of 4

type TraceOption

type TraceOption func(*traceConfig)

TraceOption specifies instrumentation configuration options.

func WithPropagators

func WithPropagators(propagators propagation.TextMapPropagator) TraceOption

WithPropagators specifies propagators to use for extracting information from the HTTP requests. If none are specified, global ones will be used.

func WithTracerProvider

func WithTracerProvider(provider oteltrace.TracerProvider) TraceOption

WithTracerProvider specifies a tracer provider to use for creating a tracer. If none is specified, the global provider is used.

Directories

Path Synopsis
Package auth provides JWT authentication middleware for gin.
Package auth provides JWT authentication middleware for gin.
Package metrics is gin metrics library, collect five metrics, "uptime", "http_request_count_total", "http_request_duration_seconds", "http_request_size_bytes", "http_response_size_bytes".
Package metrics is gin metrics library, collect five metrics, "uptime", "http_request_count_total", "http_request_duration_seconds", "http_request_size_bytes", "http_response_size_bytes".

Jump to

Keyboard shortcuts

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