package handler import ( "net/http" "github.com/dnoulet/go-first/internal/model" "github.com/dnoulet/go-first/internal/service" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/rs/zerolog/log" ) type Handler struct { skillService *service.SkillService projectService *service.ProjectService experienceService *service.ExperienceService serviceService *service.ServiceService contactService *service.ContactService } func NewHandler( skillService *service.SkillService, projectService *service.ProjectService, experienceService *service.ExperienceService, serviceService *service.ServiceService, contactService *service.ContactService, ) *Handler { return &Handler{ skillService: skillService, projectService: projectService, experienceService: experienceService, serviceService: serviceService, contactService: contactService, } } func (h *Handler) RegisterRoutes(r *gin.Engine) { api := r.Group("/api/v1") { api.GET("/health", h.HealthCheck) api.GET("/skills", h.GetSkills) api.GET("/skills/:id", h.GetSkill) api.GET("/projects", h.GetProjects) api.GET("/projects/featured", h.GetFeaturedProjects) api.GET("/projects/:id", h.GetProject) api.GET("/experience", h.GetExperience) api.GET("/services", h.GetServices) api.POST("/contact", h.SubmitContact) } } func (h *Handler) HealthCheck(c *gin.Context) { c.JSON(http.StatusOK, model.SuccessResponse(gin.H{ "status": "ok", "service": "go-first", "version": "1.0.0", })) } func (h *Handler) GetSkills(c *gin.Context) { category := c.Query("category") skills, err := h.skillService.GetAll(c.Request.Context(), category) if err != nil { log.Error().Err(err).Msg("Failed to get skills") c.JSON(http.StatusInternalServerError, model.ErrorResponse("INTERNAL_ERROR", "Failed to retrieve skills", err.Error())) return } c.JSON(http.StatusOK, model.SuccessResponse(skills)) } func (h *Handler) GetSkill(c *gin.Context) { idStr := c.Param("id") id, err := uuid.Parse(idStr) if err != nil { c.JSON(http.StatusBadRequest, model.ErrorResponse("INVALID_ID", "Invalid skill ID", err.Error())) return } skill, err := h.skillService.GetByID(c.Request.Context(), id) if err != nil { log.Error().Err(err).Str("id", idStr).Msg("Failed to get skill") c.JSON(http.StatusNotFound, model.ErrorResponse("NOT_FOUND", "Skill not found", err.Error())) return } c.JSON(http.StatusOK, model.SuccessResponse(skill)) } func (h *Handler) GetProjects(c *gin.Context) { category := c.Query("category") featured := c.Query("featured") == "true" projects, err := h.projectService.GetAll(c.Request.Context(), category, featured) if err != nil { log.Error().Err(err).Msg("Failed to get projects") c.JSON(http.StatusInternalServerError, model.ErrorResponse("INTERNAL_ERROR", "Failed to retrieve projects", err.Error())) return } c.JSON(http.StatusOK, model.SuccessResponse(projects)) } func (h *Handler) GetFeaturedProjects(c *gin.Context) { projects, err := h.projectService.GetFeatured(c.Request.Context()) if err != nil { log.Error().Err(err).Msg("Failed to get featured projects") c.JSON(http.StatusInternalServerError, model.ErrorResponse("INTERNAL_ERROR", "Failed to retrieve featured projects", err.Error())) return } c.JSON(http.StatusOK, model.SuccessResponse(projects)) } func (h *Handler) GetProject(c *gin.Context) { idStr := c.Param("id") id, err := uuid.Parse(idStr) if err != nil { c.JSON(http.StatusBadRequest, model.ErrorResponse("INVALID_ID", "Invalid project ID", err.Error())) return } project, err := h.projectService.GetByID(c.Request.Context(), id) if err != nil { log.Error().Err(err).Str("id", idStr).Msg("Failed to get project") c.JSON(http.StatusNotFound, model.ErrorResponse("NOT_FOUND", "Project not found", err.Error())) return } c.JSON(http.StatusOK, model.SuccessResponse(project)) } func (h *Handler) GetExperience(c *gin.Context) { experience, err := h.experienceService.GetAll(c.Request.Context()) if err != nil { log.Error().Err(err).Msg("Failed to get experience") c.JSON(http.StatusInternalServerError, model.ErrorResponse("INTERNAL_ERROR", "Failed to retrieve experience", err.Error())) return } c.JSON(http.StatusOK, model.SuccessResponse(experience)) } func (h *Handler) GetServices(c *gin.Context) { services, err := h.serviceService.GetAll(c.Request.Context()) if err != nil { log.Error().Err(err).Msg("Failed to get services") c.JSON(http.StatusInternalServerError, model.ErrorResponse("INTERNAL_ERROR", "Failed to retrieve services", err.Error())) return } c.JSON(http.StatusOK, model.SuccessResponse(services)) } func (h *Handler) SubmitContact(c *gin.Context) { var req model.ContactForm if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.ErrorResponse("VALIDATION_ERROR", "Invalid request body", err.Error())) return } submission, err := h.contactService.Create(c.Request.Context(), &req) if err != nil { log.Error().Err(err).Msg("Failed to create contact submission") c.JSON(http.StatusInternalServerError, model.ErrorResponse("INTERNAL_ERROR", "Failed to submit contact form", err.Error())) return } c.JSON(http.StatusCreated, model.SuccessResponse(submission)) }