package handlers import ( "net/http" "strconv" "github.com/gin-gonic/gin" "go.uber.org/zap" "github.com/kms/api-key-service/internal/domain" "github.com/kms/api-key-service/internal/services" ) // ApplicationHandler handles application-related HTTP requests type ApplicationHandler struct { appService services.ApplicationService authService services.AuthenticationService logger *zap.Logger } // NewApplicationHandler creates a new application handler func NewApplicationHandler( appService services.ApplicationService, authService services.AuthenticationService, logger *zap.Logger, ) *ApplicationHandler { return &ApplicationHandler{ appService: appService, authService: authService, logger: logger, } } // Create handles POST /applications func (h *ApplicationHandler) Create(c *gin.Context) { var req domain.CreateApplicationRequest if err := c.ShouldBindJSON(&req); err != nil { h.logger.Warn("Invalid request body", zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{ "error": "Bad Request", "message": "Invalid request body: " + err.Error(), }) return } // Get user ID from context userID, exists := c.Get("user_id") if !exists { h.logger.Error("User ID not found in context") c.JSON(http.StatusInternalServerError, gin.H{ "error": "Internal Server Error", "message": "Authentication context not found", }) return } app, err := h.appService.Create(c.Request.Context(), &req, userID.(string)) if err != nil { h.logger.Error("Failed to create application", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{ "error": "Internal Server Error", "message": "Failed to create application", }) return } h.logger.Info("Application created", zap.String("app_id", app.AppID)) c.JSON(http.StatusCreated, app) } // GetByID handles GET /applications/:id func (h *ApplicationHandler) GetByID(c *gin.Context) { appID := c.Param("id") if appID == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "Bad Request", "message": "Application ID is required", }) return } app, err := h.appService.GetByID(c.Request.Context(), appID) if err != nil { h.logger.Error("Failed to get application", zap.Error(err), zap.String("app_id", appID)) c.JSON(http.StatusNotFound, gin.H{ "error": "Not Found", "message": "Application not found", }) return } c.JSON(http.StatusOK, app) } // List handles GET /applications func (h *ApplicationHandler) List(c *gin.Context) { // Parse pagination parameters limit := 50 offset := 0 if l := c.Query("limit"); l != "" { if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 { limit = parsed } } if o := c.Query("offset"); o != "" { if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 { offset = parsed } } apps, err := h.appService.List(c.Request.Context(), limit, offset) if err != nil { h.logger.Error("Failed to list applications", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{ "error": "Internal Server Error", "message": "Failed to list applications", }) return } c.JSON(http.StatusOK, gin.H{ "data": apps, "limit": limit, "offset": offset, "count": len(apps), }) } // Update handles PUT /applications/:id func (h *ApplicationHandler) Update(c *gin.Context) { appID := c.Param("id") if appID == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "Bad Request", "message": "Application ID is required", }) return } var req domain.UpdateApplicationRequest if err := c.ShouldBindJSON(&req); err != nil { h.logger.Warn("Invalid request body", zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{ "error": "Bad Request", "message": "Invalid request body: " + err.Error(), }) return } // Get user ID from context userID, exists := c.Get("user_id") if !exists { h.logger.Error("User ID not found in context") c.JSON(http.StatusInternalServerError, gin.H{ "error": "Internal Server Error", "message": "Authentication context not found", }) return } app, err := h.appService.Update(c.Request.Context(), appID, &req, userID.(string)) if err != nil { h.logger.Error("Failed to update application", zap.Error(err), zap.String("app_id", appID)) c.JSON(http.StatusInternalServerError, gin.H{ "error": "Internal Server Error", "message": "Failed to update application", }) return } h.logger.Info("Application updated", zap.String("app_id", appID)) c.JSON(http.StatusOK, app) } // Delete handles DELETE /applications/:id func (h *ApplicationHandler) Delete(c *gin.Context) { appID := c.Param("id") if appID == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "Bad Request", "message": "Application ID is required", }) return } // Get user ID from context userID, exists := c.Get("user_id") if !exists { h.logger.Error("User ID not found in context") c.JSON(http.StatusInternalServerError, gin.H{ "error": "Internal Server Error", "message": "Authentication context not found", }) return } err := h.appService.Delete(c.Request.Context(), appID, userID.(string)) if err != nil { h.logger.Error("Failed to delete application", zap.Error(err), zap.String("app_id", appID)) c.JSON(http.StatusInternalServerError, gin.H{ "error": "Internal Server Error", "message": "Failed to delete application", }) return } h.logger.Info("Application deleted", zap.String("app_id", appID)) c.JSON(http.StatusNoContent, nil) }