兼职招募 | 51CTO 社区编辑加盟指南
大家好, 我是程序员幽鬼.
Fiber 作为一个新的 Go 框架, 似乎受追捧程度很高, Star 数飙升很快. 不知道这是不是表明, 不少 JS/Node 爱好者开始尝试学习 Go 了, 对 Go 是好事.
今天这篇文章介绍如何使用 Fiber + Gorm 构建 REST API.
1 概览
在这篇文章中, 我们将使用 Fiber[1] 框架, 它使用起来非常简单, 有一个很好的抽象层, 并且包含我们创建 API 所需的一切.
关于与数据库的交互, 我决定使用 ORM 来使整个过程更简单, 更直观, 因此我决定使用 Gorm[2], 在我看来, Gorm[3] 是 Go 世界中最受欢迎的 ORM, 并且特性很多.
2 准备工作
本文基于 Go1.17.5.
在本地创建一个目录 fibergorm, 然后进入该目录执行如下命令:
- $ go mod init GitHub.com/programmerug/fibergorm
- go: creating new go.mod: module GitHub.com/programmerug/fibergorm
接着执行如下命令, 安装我们需要的依赖:(这个先不执行, 之后通过 go mod tidy 安装)
- go get GitHub.com/gofiber/fiber/v2
- go get gorm.io/gorm
为了方便, 本教程中, 我们使用 SQLite, 因为使用了 Gorm, 所以哪种关系型数据库对核心代码没有什么影响.
3 开始编码
本文以人类的朋友 -- 狗为例.
先从定义实体开始, 它总共有四个属性:
Name - 狗的名字
Age - 狗的年龄
Breed - 狗的种族 (类型)
IsGoodBoy - 狗是否是个好孩子
类似以下内容:
- // 文件名: entities/dog.go
- package entities
- import "gorm.io/gorm"
- type Dog struct {
- gorm.Model
- Name string `json:"name"`
- Age int `json:"age"`
- Breed string `json:"breed"`
- IsGoodBoy bool `json:"is_good_boy" gorm:"default:true"`
- }
注意其中的内嵌类型 gorm.Model, 它只是定义了一些通用的字段.
- type Model struct {
- ID uint `gorm:"primarykey"`
- CreatedAt time.Time
- UpdatedAt time.Time
- DeletedAt DeletedAt `gorm:"index"`
- }
因此, 我们完全可以自己选择是否要嵌入 gorm.Model.
接着, 我们配置与数据库的连接. 一般我喜欢创建一个名为 Connect() 的函数, 它负责初始化连接, 此外还负责在我们的数据库中执行迁移 (migration), 即生成表结构:
- // 文件名: config/database.go
- package config
- import (
- "github.com/programmerug/fibergorm/entities"
- "gorm.io/driver/sqlite"
- "gorm.io/gorm"
- )
- var Database *gorm.DB
- func Connect() error {
- var err error
- Database, err = gorm.Open(SQLite.Open("fibergorm.db"), &gorm.Config{})
- if err != nil {
- panic(err)
- }
- Database.AutoMigrate(&entities.Dog{})
- return nil
- }
fibergorm.db 是最后生成的数据库文件
在程序启动时, 需要调用 Connect 函数
现在已经定义了实体并配置了到数据库的连接, 我们可以开始处理我们的处理程序. 我们的每个处理程序都将对应来自 API 的一个路由, 每个处理程序只负责执行一个操作. 首先让我们获取数据库表中的所有记录.
- // 文件名: handlers/dog.go
- package handlers
- import (
- "github.com/gofiber/fiber/v2"
- "github.com/programmerug/fibergorm/config"
- "github.com/programmerug/fibergorm/entities"
- )
- func GetDogs(c *fiber.Ctx) error {
- var dogs []entities.Dog
- config.Database.Find(&dogs)
- return c.Status(200).JSON(dogs)
- }
- // ...
现在根据将在请求参数中发送的 id 参数获取一条记录.
- // 文件名: handlers/dog.go
- package handlers
- // ...
- func GetDog(c *fiber.Ctx) error {
- id := c.Params("id")
- var dog entities.Dog
- result := config.Database.Find(&dog, id)
- if result.RowsAffected == 0 {
- return c.SendStatus(404)
- }
- return c.Status(200).JSON(&dog)
- }
- // ...
现在我们可以得到所有的记录和根据 id 获取一条记录. 但缺乏在数据库表中插入新记录的功能.
- // 文件名: handlers/dog.go
- package handlers
- // ...
- func AddDog(c *fiber.Ctx) error {
- dog := new(entities.Dog)
- if err := c.BodyParser(dog); err != nil {
- return c.Status(503).SendString(err.Error())
- }
- config.Database.Create(&dog)
- return c.Status(201).JSON(dog)
- }
- // ...
我们还需要添加更新数据库中现有记录的功能. 与我们已经实现的类似, 使用 id 参数来更新特定记录.
- // 文件名: handlers/dog.go
- package handlers
- // ...
- func UpdateDog(c *fiber.Ctx) error {
- dog := new(entities.Dog)
- id := c.Params("id")
- if err := c.BodyParser(dog); err != nil {
- return c.Status(503).SendString(err.Error())
- }
- config.Database.Where("id = ?", id).Updates(&dog)
- return c.Status(200).JSON(dog)
- }
- // ...
最后, 我们需要删除特定记录, 再次使
最后, 我们需要删除特定记录, 再次使用 id 参数从我们的数据库中删除特定记录.
- // 文件名: handlers/dog.go
- package handlers
- // ...
- func RemoveDog(c *fiber.Ctx) error {
- id := c.Params("id")
- var dog entities.Dog
- result := config.Database.Delete(&dog, id)
- if result.RowsAffected == 0 {
- return c.SendStatus(404)
- }
- return c.SendStatus(200)
- }
- // ...
现在只需要创建我们的 main 文件, 该文件将负责初始化与数据库的连接以及我们的 API 路由将在何处定义, 并且将处理程序与它们进行关联绑定.
- // 文件名: main.go
- package main
- import (
- "log"
- "github.com/gofiber/fiber/v2"
- "github.com/programmerug/fibergorm/config"
- "github.com/programmerug/fibergorm/handlers"
- )
- func main() {
- App := fiber.New()
- config.Connect()
- App.Get("/dogs", handlers.GetDogs)
- App.Get("/dogs/:id", handlers.GetDog)
- App.Post("/dogs", handlers.AddDog)
- App.Put("/dogs/:id", handlers.UpdateDog)
- App.Delete("/dogs/:id", handlers.RemoveDog)
- log.Fatal(App.Listen(":3000"))
- }
至此, 我们完成了一个简单应用的 CRUD. 涉及到 fiber 和 gorm 的 API 你应该查阅相关文档进一步了解.
最终, 项目目录如下:
├── config
│ └── database.go
├── entities
│ └── dog.go
├── fibergorm.db
├── go.mod
├── go.sum
├── handlers
│ └── dog.go
└── main.go
执行 go run main.go:
$ go run main.go
┌───────────────────────────────────────────────────┐
│ Fiber v2.24.0 │
│ http://127.0.0.1:3000 │
│ (bound on host 0.0.0.0 and port 3000) │
│ │
│ Handlers ............. 7 Processes ........... 1 │
│ Prefork ....... Disabled PID ............. 89910 │
└───────────────────────────────────────────────────┘
借助 postman,curl 之类的工具验证接口的正确性.
因为 fiber Ctx 的 BodyParser 能够解析 Context-Type 值是: application/JSON, application/xml, application/x-www-form-urlencoded, multipart/form-data 等的数据, 所以, 验证 AddDog 的可以采用你喜欢的 Content-Type.
- curl --location --request POST 'http://127.0.0.1:3000/dogs' \
- --header 'Content-Type: application/json' \
- --data '{name:" 旺财 ",age:3,breed:" 狼狗 ",is_good_boy:true}'
可以通过下载 https://sqlitebrowser.org/dl/ 这个 SQLite 工具查看数据是否保存成功.
细心的读者可能会发现, 生成的数据表字段顺序是根据 Dog 中的字段定义顺序确定的. 有强迫症的人可能接受不了, 因此实际中你可以不嵌入 gorm.Model, 而是自己定义相关字段.
总结
本文实现了 CRUD 的功能, 希望大家实际动手, 这样才能够真正掌握.
本文参考 https://dev.to/franciscomendes10866/how-to-build-rest-api-using-go-fiber-and-gorm-orm-2jbe.
本文完整代码: https://github.com/programmerug/fibergorm.
参考资料
[1]Fiber: https://gofiber.io/
[2]Gorm: https://gorm.io/
[3]Gorm: https://gorm.io/
来源: http://developer.51cto.com/art/202201/698311.htm