Serie: Go
go
184 líneas
· Actualizado 2026-04-18
goods_handler.go
Go/Baasid/internal/handlers/goods_handler.go
package handlers
import (
"errors"
"net/http"
"baasid/internal/dto"
"baasid/internal/middleware"
"baasid/internal/models"
"baasid/internal/repository"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"gorm.io/gorm"
)
// GoodsHandler implements authenticated goods CRUD routes.
//
// Every handler assumes JWTAuth middleware has already validated the token
// and stored the operator's UUID in the Echo context (see middleware package).
type GoodsHandler struct {
goods *repository.GoodsRepository
}
// NewGoodsHandler constructs the handler with its repository dependency.
func NewGoodsHandler(goods *repository.GoodsRepository) *GoodsHandler {
return &GoodsHandler{goods: goods}
}
// toResponse maps a persistence model to the public JSON shape from the spec
// (_id + goods_name).
func toResponse(g *models.Goods) dto.GoodsResponse {
return dto.GoodsResponse{
ID: g.ID.String(),
GoodsName: g.Name,
}
}
// Add godoc
// @Summary 新增商品
// @Description 建立一筆商品;需帶入有效 JWT。成功回傳新商品的 `_id` 與 `goods_name`。
// @Tags goods
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param body body dto.GoodsCreateRequest true "商品名稱 goods_name"
// @Success 200 {object} dto.GoodsResponse "成功"
// @Failure 403 {object} dto.ErrorMessage "權限不足(未帶 Token 或 Token 無效)"
// @Failure 500 {object} dto.ErrorMessage "系統錯誤"
// @Router /goods/add [post]
func (h *GoodsHandler) Add(c echo.Context) error {
var req dto.GoodsCreateRequest
if err := c.Bind(&req); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, dto.ErrorMessage{Message: "無效的 JSON 格式"})
}
if req.GoodsName == "" {
return echo.NewHTTPError(http.StatusBadRequest, dto.ErrorMessage{Message: "goods_name 不可為空"})
}
operator := middleware.GetUserID(c)
g, err := h.goods.Create(operator, req.GoodsName)
if err != nil {
c.Logger().Errorf("goods create: %v", err)
return echo.NewHTTPError(http.StatusInternalServerError, dto.ErrorMessage{Message: "系統錯誤"})
}
return c.JSON(http.StatusOK, toResponse(g))
}
// List godoc
// @Summary 取得所有商品
// @Description 回傳陣列,每個元素為 `_id` 與 `goods_name`。
// @Tags goods
// @Produce json
// @Security BearerAuth
// @Success 200 {array} dto.GoodsResponse "成功"
// @Failure 403 {object} dto.ErrorMessage "權限不足"
// @Failure 500 {object} dto.ErrorMessage "系統錯誤"
// @Router /goods [get]
func (h *GoodsHandler) List(c echo.Context) error {
list, err := h.goods.ListAll()
if err != nil {
c.Logger().Errorf("goods list: %v", err)
return echo.NewHTTPError(http.StatusInternalServerError, dto.ErrorMessage{Message: "系統錯誤"})
}
out := make([]dto.GoodsResponse, 0, len(list))
for i := range list {
out = append(out, toResponse(&list[i]))
}
return c.JSON(http.StatusOK, out)
}
// GetByID godoc
// @Summary 取得指定商品
// @Description 路徑參數 `id` 為商品 UUID(字串格式)。
// @Tags goods
// @Produce json
// @Security BearerAuth
// @Param id path string true "商品代號 (UUID)"
// @Success 200 {object} dto.GoodsResponse "成功"
// @Failure 403 {object} dto.ErrorMessage "權限不足"
// @Failure 404 {object} dto.ErrorMessage "找不到商品"
// @Failure 500 {object} dto.ErrorMessage "系統錯誤"
// @Router /goods/{id} [get]
func (h *GoodsHandler) GetByID(c echo.Context) error {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, dto.ErrorMessage{Message: "id 必須為 UUID"})
}
g, err := h.goods.FindByID(id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return echo.NewHTTPError(http.StatusNotFound, dto.ErrorMessage{Message: "找不到商品"})
}
c.Logger().Errorf("goods get: %v", err)
return echo.NewHTTPError(http.StatusInternalServerError, dto.ErrorMessage{Message: "系統錯誤"})
}
return c.JSON(http.StatusOK, toResponse(g))
}
// Update godoc
// @Summary 更新商品
// @Description 依 `id` 更新商品名稱;`up_user` / `up_datetime` 由後端寫入。
// @Tags goods
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path string true "商品代號 (UUID)"
// @Param body body dto.GoodsUpdateRequest true "新商品名稱"
// @Success 200 {object} dto.GoodsResponse "成功"
// @Failure 403 {object} dto.ErrorMessage "權限不足"
// @Failure 404 {object} dto.ErrorMessage "找不到商品"
// @Failure 500 {object} dto.ErrorMessage "系統錯誤"
// @Router /goods/{id} [put]
func (h *GoodsHandler) Update(c echo.Context) error {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, dto.ErrorMessage{Message: "id 必須為 UUID"})
}
var req dto.GoodsUpdateRequest
if err := c.Bind(&req); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, dto.ErrorMessage{Message: "無效的 JSON 格式"})
}
if req.GoodsName == "" {
return echo.NewHTTPError(http.StatusBadRequest, dto.ErrorMessage{Message: "goods_name 不可為空"})
}
operator := middleware.GetUserID(c)
g, err := h.goods.UpdateName(id, operator, req.GoodsName)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return echo.NewHTTPError(http.StatusNotFound, dto.ErrorMessage{Message: "找不到商品"})
}
c.Logger().Errorf("goods update: %v", err)
return echo.NewHTTPError(http.StatusInternalServerError, dto.ErrorMessage{Message: "系統錯誤"})
}
return c.JSON(http.StatusOK, toResponse(g))
}
// Delete godoc
// @Summary 刪除商品
// @Description 依 `id` 刪除商品;成功僅回 HTTP 200(無 Body 亦可,此處回空 JSON 物件方便客戶端解析)。
// @Tags goods
// @Security BearerAuth
// @Param id path string true "商品代號 (UUID)"
// @Success 200 {object} map[string]string "成功,例如 {\"status\":\"ok\"}"
// @Failure 403 {object} dto.ErrorMessage "權限不足"
// @Failure 404 {object} dto.ErrorMessage "找不到商品"
// @Failure 500 {object} dto.ErrorMessage "系統錯誤"
// @Router /goods/{id} [delete]
func (h *GoodsHandler) Delete(c echo.Context) error {
id, err := uuid.Parse(c.Param("id"))
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, dto.ErrorMessage{Message: "id 必須為 UUID"})
}
if err := h.goods.DeleteByID(id); err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return echo.NewHTTPError(http.StatusNotFound, dto.ErrorMessage{Message: "找不到商品"})
}
c.Logger().Errorf("goods delete: %v", err)
return echo.NewHTTPError(http.StatusInternalServerError, dto.ErrorMessage{Message: "系統錯誤"})
}
// Spec: HTTP 200 on success. Empty JSON keeps Content-Type consistent.
return c.JSON(http.StatusOK, echo.Map{})
}
Artículos relacionados
Go
go
Actualizado 2026-04-18
main.go
main.go — go source code from the Go learning materials (Go/Baasid/cmd/hashpw/main.go).
Leer artículo →
Go
go
Actualizado 2026-04-18
main.go
main.go — go source code from the Go learning materials (Go/Baasid/cmd/server/main.go).
Leer artículo →
Go
go
Actualizado 2026-04-18
docs.go
docs.go — go source code from the Go learning materials (Go/Baasid/docs/docs.go).
Leer artículo →
Go
go
Actualizado 2026-04-18
jwt.go
jwt.go — go source code from the Go learning materials (Go/Baasid/internal/auth/jwt.go).
Leer artículo →
Go
go
Actualizado 2026-04-18
password.go
password.go — go source code from the Go learning materials (Go/Baasid/internal/auth/password.go).
Leer artículo →
Go
go
Actualizado 2026-04-18
password_test.go
password_test.go — go source code from the Go learning materials (Go/Baasid/internal/auth/password_test.go).
Leer artículo →