package routers import ( "FamilyHub/src/api/dto" "FamilyHub/src/api/requests" "FamilyHub/src/api/services" receiptServiceIntegration "FamilyHub/src/integrations/receiptProvider" "database/sql" "errors" "log" "net/http" "runtime/debug" "github.com/gin-gonic/gin" ) func logError(c *gin.Context, scope string, err error) { log.Printf( "%s failed: method=%s path=%s route=%s error=%v", scope, c.Request.Method, c.Request.URL.Path, c.FullPath(), err, ) } func logInternalError(c *gin.Context, scope string, err error) { log.Printf( "%s failed: method=%s path=%s route=%s error=%v\n%s", scope, c.Request.Method, c.Request.URL.Path, c.FullPath(), err, debug.Stack(), ) } func handleReceiptError(c *gin.Context, err error) { var externalErr *receiptServiceIntegration.ExternalServiceError switch { case errors.Is(err, receiptServiceIntegration.ErrReceiptNotFound): c.JSON(http.StatusNotFound, dto.ErrorResponse{Message: err.Error()}) case errors.As(err, &externalErr): log.Printf( "receipt external service error: method=%s path=%s upstream_status=%d upstream_body=%q", c.Request.Method, c.Request.URL.Path, externalErr.StatusCode, externalErr.Body, ) logError(c, "receipt external service", err) switch externalErr.StatusCode { case http.StatusForbidden, http.StatusTooManyRequests: c.JSON(http.StatusServiceUnavailable, dto.ErrorResponse{Message: "receipt service temporarily unavailable"}) default: c.JSON(http.StatusBadGateway, dto.ErrorResponse{Message: "receipt service error"}) } default: logInternalError(c, "receipt request", err) c.JSON(http.StatusInternalServerError, dto.ErrorResponse{Message: "internal server error"}) } } func handleActivityError(c *gin.Context, err error) { logInternalError(c, "activity request", err) c.JSON(http.StatusInternalServerError, dto.ErrorResponse{Message: "internal server error"}) } func handleFamilyError(c *gin.Context, err error) { switch { case errors.Is(err, services.ErrFamilyNotFound): c.JSON(http.StatusNotFound, dto.ErrorResponse{Message: err.Error()}) case errors.Is(err, sql.ErrNoRows): c.JSON(http.StatusNotFound, dto.ErrorResponse{Message: "family not found"}) case errors.Is(err, requests.ErrFamilyNameRequired): c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: err.Error()}) default: logInternalError(c, "family request", err) c.JSON(http.StatusInternalServerError, dto.ErrorResponse{Message: "internal server error"}) } } func handleUserError(c *gin.Context, err error) { switch { case errors.Is(err, services.ErrUserNotFound): c.JSON(http.StatusNotFound, dto.ErrorResponse{Message: err.Error()}) case errors.Is(err, services.ErrInvalidPatch): c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: err.Error()}) case errors.Is(err, services.ErrTelegramIDMissing): c.JSON(http.StatusBadRequest, dto.ErrorResponse{Message: err.Error()}) default: logInternalError(c, "user request", err) c.JSON(http.StatusInternalServerError, dto.ErrorResponse{Message: "internal server error"}) } }