package handlers import ( "net/http" "time" "github.com/gin-gonic/gin" "veza-backend-api/internal/errors" ) // ErrorResponse représente le format d'erreur standardisé selon ORIGIN_API_SPECIFICATION // GO-014: Harmonisation format erreurs HTTP type ErrorResponse struct { Error struct { Code int `json:"code"` Message string `json:"message"` Details []errors.ErrorDetail `json:"details,omitempty"` RequestID string `json:"request_id,omitempty"` Timestamp string `json:"timestamp"` Context map[string]interface{} `json:"context,omitempty"` } `json:"error"` } // RespondWithAppError répond avec une AppError au format standardisé ORIGIN_API_SPECIFICATION // GO-014: Harmonisation format erreurs HTTP selon ORIGIN_API_SPECIFICATION func RespondWithAppError(c *gin.Context, appErr *errors.AppError) { statusCode := mapErrorCodeToHTTPStatus(appErr.Code) errorData := struct { Code int `json:"code"` Message string `json:"message"` Details []errors.ErrorDetail `json:"details,omitempty"` RequestID string `json:"request_id,omitempty"` Timestamp string `json:"timestamp"` Context map[string]interface{} `json:"context,omitempty"` }{ Code: int(appErr.Code), Message: appErr.Message, Details: appErr.Details, RequestID: c.GetString("request_id"), Timestamp: time.Now().UTC().Format(time.RFC3339), Context: appErr.Context, } c.JSON(statusCode, APIResponse{ Success: false, Data: nil, Error: errorData, }) } // RespondWithError répond avec un code d'erreur et un message au format standardisé // GO-014: Harmonisation format erreurs HTTP selon ORIGIN_API_SPECIFICATION func RespondWithError(c *gin.Context, code int, message string, details ...errors.ErrorDetail) { statusCode := mapErrorCodeToHTTPStatus(errors.ErrorCode(code)) errorData := struct { Code int `json:"code"` Message string `json:"message"` Details []errors.ErrorDetail `json:"details,omitempty"` RequestID string `json:"request_id,omitempty"` Timestamp string `json:"timestamp"` }{ Code: code, Message: message, Details: details, RequestID: c.GetString("request_id"), Timestamp: time.Now().UTC().Format(time.RFC3339), } c.JSON(statusCode, APIResponse{ Success: false, Data: nil, Error: errorData, }) } // mapErrorCodeToHTTPStatus mappe les codes d'erreur ORIGIN vers les codes HTTP // GO-014: Harmonisation format erreurs HTTP selon ORIGIN_API_SPECIFICATION func mapErrorCodeToHTTPStatus(code errors.ErrorCode) int { // Authentication & Authorization (1000-1999) if code >= 1000 && code < 2000 { switch code { case 1000, 1001, 1002, 1007, 1008: // Invalid credentials, token expired/invalid, 2FA return http.StatusUnauthorized case 1003, 1004, 1005, 1006: // Insufficient permissions, account issues return http.StatusForbidden default: return http.StatusUnauthorized } } // Validation Errors (2000-2999) if code >= 2000 && code < 3000 { return http.StatusBadRequest } // Resource Errors (3000-3999) if code >= 3000 && code < 4000 { switch code { case 3000, 3003: // Not found, deleted return http.StatusNotFound case 3001, 3002: // Already exists, conflict return http.StatusConflict case 3004: // Locked return http.StatusLocked case 3005: // Quota exceeded return http.StatusForbidden default: return http.StatusNotFound } } // Business Logic Errors (4000-4999) if code >= 4000 && code < 5000 { return http.StatusUnprocessableEntity } // Rate Limiting (5000-5099) if code >= 5000 && code < 5100 { return http.StatusTooManyRequests } // External Services (6000-6999) if code >= 6000 && code < 7000 { return http.StatusBadGateway } // Internal Errors (9000-9999) if code >= 9000 && code < 10000 { return http.StatusInternalServerError } // Default return http.StatusInternalServerError }