package handlers import ( "encoding/json" "net/http" "strconv" "github.com/fish/language/backend/internal/models" "github.com/fish/language/backend/internal/services" "github.com/go-chi/chi/v5" ) // CategoryHandler handles HTTP requests for categories. type CategoryHandler struct { svc *services.CategoryService } // NewCategoryHandler creates a new CategoryHandler. func NewCategoryHandler(svc *services.CategoryService) *CategoryHandler { return &CategoryHandler{svc: svc} } // Register mounts category routes. func (h *CategoryHandler) Register(r chi.Router) { r.Get("/categories", h.List) r.Post("/categories", h.Create) r.Get("/categories/{id}", h.Get) r.Put("/categories/{id}", h.Update) r.Delete("/categories/{id}", h.Delete) } // List returns all categories. func (h *CategoryHandler) List(w http.ResponseWriter, r *http.Request) { items, err := h.svc.List(r.Context()) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, items) } // Get returns a category by id. func (h *CategoryHandler) Get(w http.ResponseWriter, r *http.Request) { id, err := parseID(r) if err != nil { RespondError(w, http.StatusBadRequest, 10002, "invalid id") return } item, err := h.svc.Get(r.Context(), id) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, item) } // Create creates a new category. func (h *CategoryHandler) Create(w http.ResponseWriter, r *http.Request) { var req models.CreateCategoryRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { RespondError(w, http.StatusBadRequest, 10003, "invalid request body") return } if req.Name == "" { RespondError(w, http.StatusBadRequest, 10004, "name is required") return } item, err := h.svc.Create(r.Context(), req) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondJSON(w, http.StatusCreated, modelsAPIResponse{Code: 0, Message: "created", Data: item}) } // Update updates a category. func (h *CategoryHandler) Update(w http.ResponseWriter, r *http.Request) { id, err := parseID(r) if err != nil { RespondError(w, http.StatusBadRequest, 10002, "invalid id") return } var req models.UpdateCategoryRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { RespondError(w, http.StatusBadRequest, 10003, "invalid request body") return } if req.Name == "" { RespondError(w, http.StatusBadRequest, 10004, "name is required") return } item, err := h.svc.Update(r.Context(), id, req) if err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, item) } // Delete removes a category. func (h *CategoryHandler) Delete(w http.ResponseWriter, r *http.Request) { id, err := parseID(r) if err != nil { RespondError(w, http.StatusBadRequest, 10002, "invalid id") return } if err := h.svc.Delete(r.Context(), id); err != nil { status, code, msg := MapError(err) RespondError(w, status, code, msg) return } RespondSuccess(w, nil) } func parseID(r *http.Request) (int32, error) { idStr := chi.URLParam(r, "id") id64, err := strconv.ParseInt(idStr, 10, 32) if err != nil { return 0, err } return int32(id64), nil }