package middleware import ( "errors" "net/http" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" "github.com/router-for-me/CLIProxyAPI/v6/internal/application/dto" domainerrors "github.com/router-for-me/CLIProxyAPI/v6/internal/domain/errors" ) // ErrorHandler returns a middleware that handles domain errors func ErrorHandler(logger *logrus.Logger) gin.HandlerFunc { return func(c *gin.Context) { c.Next() // Check if there are any errors if len(c.Errors) == 0 { return } // Get the last error err := c.Errors.Last().Err requestID := c.GetString("request_id") // Handle domain errors if domainErr, ok := err.(*domainerrors.DomainError); ok { handleDomainError(c, domainErr, requestID, logger) return } // Handle wrapped domain errors var domainErr *domainerrors.DomainError if errors.As(err, &domainErr) { handleDomainError(c, domainErr, requestID, logger) return } // Unknown error - log full details but return generic message logger.WithError(err). WithField("request_id", requestID). WithField("path", c.Request.URL.Path). Error("Unhandled error") c.JSON(http.StatusInternalServerError, dto.InternalErrorResponse{ Success: false, Error: "An unexpected error occurred", RequestID: requestID, }) } } func handleDomainError(c *gin.Context, err *domainerrors.DomainError, requestID string, logger *logrus.Logger) { // Log with appropriate level based on status code entry := logger.WithError(err). WithField("request_id", requestID). WithField("error_code", err.Code). WithField("path", c.Request.URL.Path) statusCode := err.HTTPStatusCode() if statusCode >= 500 { entry.Error("Server error") } else if statusCode >= 400 { entry.Warn("Client error") } // Return structured error response c.JSON(statusCode, dto.ErrorResponse{ Success: false, Error: dto.ErrorInfo{ Code: string(err.Code), Message: err.Message, Details: err.Details, }, RequestID: requestID, }) }