Fiber CRUD 实现只需三步:定义嵌入 gorm.Model 的结构体(自定义主键需手动声明)、编写带错误处理的 handler(注意 Status() 显式设码)、注册符合 v2 语法的路由(如 /games/:id 配 c.Params("id"));务必显式调用 godotenv.Load() 加载环境变量。

直接上手就能跑通的 Fiber CRUD 实现,核心就三件事:定义模型、写 handler、注册路由。不需要额外抽象层,GORM 自带的 Create、First、Save、Delete 就够用。
定义 GORM 模型并启用自动迁移
模型必须嵌入 gorm.Model 或手动声明主键和时间字段,否则 AutoMigrate 会失败或生成不符合预期的表结构。
-
gorm.Model自带ID、CreatedAt、UpdatedAt、DeletedAt,适合快速起步 - 如果用自定义主键(比如
uuid),就不能嵌入gorm.Model,得自己写字段并加gorm:"primarykey" - 迁移前确保数据库已存在,
AutoMigrate不会自动创建 database,只建表 - PostgreSQL 下注意字段名默认转为小写下划线(如
IsPublished→is_published),想保持驼峰需加 tag:gorm:"column:is_published"
示例模型:
type Game struct {
gorm.Model
Title string `json:"title"`
Genre string `json:"genre"`
ReleaseYear int `json:"release_year"`
}
写 handler 时别漏掉错误处理和状态码
Fiber 的 c.Status() 和 c.JSON() 是分离的,不显式调用 Status() 就默认返回 200,容易掩盖 404、400 等语义错误。
- 查不到记录时用
result.Error == gorm.ErrRecordNotFound判断,别只看result.RowsAffected == 0 - 创建失败时,
db.Create(&game).Error可能是唯一错误源,但要检查是否为空再返回 400 - 更新操作推荐用
db.First(&game, id).Error先查再改,避免对不存在 ID 调用Save导致静默插入 - 删除建议用
db.Delete(&Game{}, id)而非先查后删,减少一次查询开销
典型创建 handler:
func createGame(c *fiber.Ctx) error {
var game Game
if err := c.BodyParser(&game); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "invalid request body"})
}
result := db.Create(&game)
if result.Error != nil {
return c.Status(400).JSON(fiber.Map{"error": result.Error.Error()})
}
return c.Status(201).JSON(game)
}
注册路由要匹配 Fiber v2 的参数语法
Fiber v2 使用冒号前缀表示路径参数,比如 /games/:id,但获取时必须用 c.Params("id"),不是 c.Param("id")(那是 Gin 的写法)。
-
:id是占位符,*id才是通配符(匹配剩余路径),别混用 - 批量操作如
GET /games?limit=10&offset=0,要用c.Query("limit")解析,不是c.Params - 路由组(
app.Group("/api"))建议提前加,避免所有接口裸露在根路径 - 别忘了给
DELETE /games/:id加c.Params("id")校验是否为数字,否则传字符串会触发 GORM 类型转换 panic
环境变量加载必须显式调用 godotenv.Load
.env 文件不会被 Go 自动读取,不调 godotenv.Load(),os.Getenv("DB_HOST") 永远返回空字符串 —— 这是本地开发最常卡住的点。
- 必须在
main()开头、任何数据库初始化之前执行godotenv.Load() - 如果
.env不在项目根目录,要传路径:godotenv.Load("./config/.env") - 生产环境通常不依赖
.env,而是靠系统级 ENV,所以本地测试务必确认godotenv已安装且调用成功 - 建议加一行日志:
log.Printf("DB_HOST=%s", os.Getenv("DB_HOST")),启动时立刻验证是否加载成功
启动代码片段:
func main() {
godotenv.Load() // ← 这行不能少
db := connectDB()
app := fiber.New()
app.Get("/games", listGames)
app.Post("/games", createGame)
app.Get("/games/:id", getGame)
app.Put("/games/:id", updateGame)
app.Delete("/games/:id", deleteGame)
log.Fatal(app.Listen(":3000"))
}
真正麻烦的从来不是写几个 handler,而是数据库连接没起来、环境变量漏加载、ID 类型解析失败这三类问题——它们不会报编译错误,但一运行就 500 或空响应,排查时容易绕远路。


















