package api import ( "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/simpletodoapp/go-todo-app/internal/dto" "github.com/simpletodoapp/go-todo-app/internal/service" ) // TodoHandler handles todo-related API requests type TodoHandler struct { todoService *service.TodoService } // NewTodoHandler creates a new todo handler func NewTodoHandler(todoService *service.TodoService) *TodoHandler { return &TodoHandler{todoService: todoService} } // RegisterRoutes registers the todo routes func (h *TodoHandler) RegisterRoutes(router *gin.RouterGroup) { todos := router.Group("/todos") { todos.GET("", h.GetTodos) todos.POST("", h.CreateTodo) todos.GET("/:id", h.GetTodo) todos.PUT("/:id", h.UpdateTodo) todos.DELETE("/:id", h.DeleteTodo) } } // GetTodos handles GET /api/todos // Returns a list of todos with optional filtering and pagination func (h *TodoHandler) GetTodos(c *gin.Context) { // Parse query parameters skip, _ := strconv.Atoi(c.DefaultQuery("skip", "0")) limit, _ := strconv.Atoi(c.DefaultQuery("limit", "100")) var completed *bool if completedStr, exists := c.GetQuery("completed"); exists { completedBool, err := strconv.ParseBool(completedStr) if err == nil { completed = &completedBool } } // Get todos from service todos, err := h.todoService.GetTodos(skip, limit, completed) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, todos) } // GetTodo handles GET /api/todos/:id // Returns a specific todo by ID func (h *TodoHandler) GetTodo(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID format"}) return } todo, err := h.todoService.GetTodoByID(uint(id)) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if todo == nil { c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"}) return } c.JSON(http.StatusOK, todo) } // CreateTodo handles POST /api/todos // Creates a new todo func (h *TodoHandler) CreateTodo(c *gin.Context) { var todoCreate dto.TodoCreate if err := c.ShouldBindJSON(&todoCreate); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } todo, err := h.todoService.CreateTodo(todoCreate) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, todo) } // UpdateTodo handles PUT /api/todos/:id // Updates an existing todo func (h *TodoHandler) UpdateTodo(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID format"}) return } var todoUpdate dto.TodoUpdate if err := c.ShouldBindJSON(&todoUpdate); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } todo, err := h.todoService.UpdateTodo(uint(id), todoUpdate) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if todo == nil { c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"}) return } c.JSON(http.StatusOK, todo) } // DeleteTodo handles DELETE /api/todos/:id // Deletes a todo func (h *TodoHandler) DeleteTodo(c *gin.Context) { id, err := strconv.ParseUint(c.Param("id"), 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID format"}) return } deleted, err := h.todoService.DeleteTodo(uint(id)) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if !deleted { c.JSON(http.StatusNotFound, gin.H{"error": "Todo not found"}) return } c.Status(http.StatusNoContent) }