全书目录

第三十三篇:Fiber 完全指南 —— 极简高压快线城区宇宙

第二十章:一个能长大的 Fiber 服务骨架,应该长什么样

1 分钟 158 字 第 631 / 962 个阅读单元

如果你现在要在项目里新增一片“订单快线区”,可以按这个节奏搭:

text
cmd/
  server/
    main.go

internal/
  app/
    app.go
  http/
    middleware/
      auth.go
      errors.go
    routes/
      health.go
      orders.go
    dto/
      order.go
  service/
    order_service.go
  repo/
    order_repo.go

核心入口可以像这样:

go
package app

import (
    "errors"

    "github.com/go-playground/validator/v10"
    "github.com/gofiber/fiber/v3"
    "github.com/gofiber/fiber/v3/middleware/logger"
    recoverer "github.com/gofiber/fiber/v3/middleware/recover"
    "github.com/gofiber/fiber/v3/middleware/requestid"
)

type structValidator struct {
    validate *validator.Validate
}

func (v *structValidator) Validate(out any) error {
    return v.validate.Struct(out)
}

func New() *fiber.App {
    app := fiber.New(fiber.Config{
        StructValidator: &structValidator{validate: validator.New()},
        ErrorHandler: func(c fiber.Ctx, err error) error {
            code := fiber.StatusInternalServerError
            var e *fiber.Error
            if errors.As(err, &e) {
                code = e.Code
            }
            return c.Status(code).JSON(fiber.Map{
                "code":    code,
                "message": err.Error(),
            })
        },
    })

    app.Use(requestid.New())
    app.Use(logger.New())
    app.Use(recoverer.New())

    app.Get("/health", func(c fiber.Ctx) error {
        return c.JSON(fiber.Map{"status": "ok"})
    })

    api := app.Group("/api")
    v1 := api.Group("/v1")

    v1.Get("/orders/:id", func(c fiber.Ctx) error {
        return c.JSON(fiber.Map{
            "id": c.Params("id"),
        })
    })

    v1.Post("/orders", func(c fiber.Ctx) error {
        type CreateOrderReq struct {
            ProductID string `json:"productId" validate:"required"`
            Quantity  int    `json:"quantity" validate:"required,gte=1"`
        }

        req := new(CreateOrderReq)
        if err := c.Bind().Body(req); err != nil {
            return err
        }

        return c.Status(fiber.StatusCreated).JSON(fiber.Map{
            "message": "created",
            "data":    req,
        })
    })

    return app
}

这份骨架体现了 Fiber 项目最值得坚持的几条纪律:

  • 入口层只管接请求和回响应
  • Bind + Validate 先把输入卡干净
  • ErrorHandler 做统一事故口径
  • 中间件链统一管理横切逻辑
  • 业务逻辑别全塞进 handler