package server import ( "net/http" "runtime/debug" "time" "git.linuxforward.com/byom/byom-golang-lib/pkg/errors" "github.com/gin-gonic/gin" "github.com/google/uuid" ) func (s *Server) corsMiddleware() gin.HandlerFunc { return func(c *gin.Context) { origin := c.Request.Header.Get("Origin") if len(s.config.AllowedOrigins) == 0 { s.logger.Warn("no allowed origins configured") } allowed := false for _, allowedOrigin := range s.config.AllowedOrigins { if origin == allowedOrigin { c.Writer.Header().Set("Access-Control-Allow-Origin", origin) allowed = true break } } if !allowed && origin != "" { s.logger.WithField("origin", origin).Warn("blocked request from unauthorized origin") } c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-Request-ID") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(http.StatusNoContent) return } c.Next() } } func (s *Server) requestIDMiddleware() gin.HandlerFunc { return func(c *gin.Context) { requestID := c.GetHeader("X-Request-ID") if requestID == "" { requestID = uuid.New().String() } c.Set("RequestID", requestID) c.Header("X-Request-ID", requestID) c.Next() } } func (s *Server) loggerMiddleware() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery c.Next() s.logger.WithFields(map[string]interface{}{ "status_code": c.Writer.Status(), "method": c.Request.Method, "path": path, "query": query, "ip": c.ClientIP(), "latency": time.Since(start), "request_id": c.GetString("RequestID"), "user_agent": c.Request.UserAgent(), }).Info("request completed") } } func (s *Server) recoveryMiddleware() gin.HandlerFunc { return func(c *gin.Context) { defer func() { if err := recover(); err != nil { requestID := c.GetString("RequestID") s.logger.WithFields(map[string]interface{}{ "error": err, "request_id": requestID, "stack": string(debug.Stack()), }).Error("panic recovered") c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ "error": errors.ErrInternalServer.Error(), "request_id": requestID, }) } }() c.Next() } } func (s *Server) errorHandlerMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Next() if len(c.Errors) > 0 { err := c.Errors.Last().Err requestID := c.GetString("RequestID") // Log the error with appropriate level and details s.logger.WithFields(map[string]interface{}{ "error": err.Error(), "request_id": requestID, }).Error("request error") // Determine status code based on error type var statusCode int var response gin.H switch { case errors.Is(err, errors.ErrNotFound): statusCode = http.StatusNotFound case errors.Is(err, errors.ErrUnauthorized): statusCode = http.StatusUnauthorized case errors.Is(err, errors.ErrInvalidInput): statusCode = http.StatusBadRequest default: statusCode = http.StatusInternalServerError } response = gin.H{ "error": err.Error(), "request_id": requestID, } c.JSON(statusCode, response) } } }