package middleware import ( "regexp" "github.com/google/uuid" "github.com/labstack/echo/v4" ) // validRequestID matches alphanumeric characters and hyphens, 1-64 chars. var validRequestID = regexp.MustCompile(`^[a-zA-Z0-9\-]{1,64}$`) const ( // HeaderXRequestID is the header key for request correlation IDs HeaderXRequestID = "X-Request-ID" // ContextKeyRequestID is the echo context key for the request ID ContextKeyRequestID = "request_id" ) // RequestIDMiddleware generates a UUID per request, sets it as X-Request-ID header, // and stores it in the echo context for downstream use. func RequestIDMiddleware() echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // Use existing request ID from header if present and valid, otherwise generate one. // Sanitize to alphanumeric + hyphens only (max 64 chars) to prevent // log injection via control characters or overly long values. reqID := c.Request().Header.Get(HeaderXRequestID) if reqID == "" || !validRequestID.MatchString(reqID) { reqID = uuid.New().String() } // Store in context c.Set(ContextKeyRequestID, reqID) // Set response header c.Response().Header().Set(HeaderXRequestID, reqID) return next(c) } } } // GetRequestID extracts the request ID from the echo context func GetRequestID(c echo.Context) string { if id, ok := c.Get(ContextKeyRequestID).(string); ok { return id } return "" }