Go:基于 MongoDB 构建 REST API -Fiber 版

网友投稿 265 2023-05-22

大家好,我是程序员幽鬼。

之前分享过一篇文章:《项目实战:使用 Fiber + Gorm 构建 REST API》,数据库使用的是 SQLite。今天分享一篇基于 MongoDB 构建 REST API 的文章,使用的依然是 Fiber 框架。

1、准备工作

开始之前,先要准备好 MongoDB。这里我们不自己安装 MongoDB,而是使用云。Mongo 提供了免费使用的。

配置 MongoDB

如果没有 MongoDB 账号,先注册一个:https://www.mongodb.com/zh-cn/cloud/atlas/register。有账号直接登录即可。然后新建一个项目(project):

New Project

项目名称你可以取一个你喜欢的名字,比如 golang-api,然后 Next:

enter project name

接着直接点击 Create Project 即可:

Create Project

然后,点击 Build a Database:

Build a Database

选择免费的 Shared:

Shared highlighted in red

点击 Create Cluster 创建集群,需要等一些时间。(其他用默认即可)

Creating a cluster

接着需要创建能够访问该数据库的用户。点击Create User,如果需要保证安全性,可以限制 IP。然后点击 Finish and Close 即可。

Create user

你也可以不限制 IP,毕竟我们只是练习、测试项目。(如果你下面运行程序,发现连不上 MongoDB,就考虑把 IP 限制直接去掉)

Add IP

保存后,可以看到 Database Deployments 界面:

Database Screen

初始化 Go 项目

在 GitHub 创建项目:fibermongo,clone 到本地,然后初始化:

复制$ go mod init github.com/programmerug/fibermongo go: creating new go.mod: module github.com/programmerug/fibermongo 1.2.

安装以下两个依赖:

复制$ go get -v github.com/gofiber/fiber/v2 $ go get -v go.mongodb.org/mongo-driver/mongo 1.2.

接着在目录下创建 main.go,输入如下内容:

复制package main import ( "github.com/gofiber/fiber/v2" ) func main() { app := fiber.New() app.Get("/", func(c *fiber.Ctx) error { return c.JSON(&fiber.Map{"welcome": "Hello from Fiber + MongoDB"}) }) app.Listen(":2022") } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.

启动 go run main.go,然后通过 curlie[1] 测试(这是 Go 实现的类似 curl 工具,易用性类似 httpie):

复制$ curlie localhost:2022 HTTP/1.1 200 OK Date: Mon, 07 Feb 2022 09:05:48 GMT Content-Type: application/json Content-Length: 40 { "welcome": "Hello from Fiber + MongoDB" } 1.2.3.4.5.6.7.8.9.

2、目录结构

创建如下目录,注意其中的注释:

复制. ├── config 用于项目配置文件 ├── controller 用于应用程序逻辑 ├── go.mod ├── go.sum ├── main.go ├── model 用于数据和数据库逻辑 ├── response 用于描述我们希望 API 给出的响应的文件 └── route 用于 URL 模式和处理程序信息 1.2.3.4.5.6.7.8.9.

3、配置连接到 MongoDB

为了让我们的程序连接到数据库 MongoDB,跟 MySQL 等类似,需要连接字符串。

在上面 MongoDB 的 Database Deployments 页面,点击 Connect 按钮:

Connect to database

接着点击 Connect your application,然后驱动选择 Go,及其版本。

connect application

然后复制:

Copy connection string

设置环境变量

在项目根目录创建 .env 文件,增加 MONGOURI:

复制MONGOURI=mongodb+srv://:@cluster0.k0oen.mongodb.net/myFirstDatabase?retryWrites=true&w=majority 1.

注意替换其中的 user 和 password 为你开头设置的。

接着需要写代码读取环境变量。因为环境变量通过 key=value 的简单形式保存在文件,因此我们使用一个对应的第三方库:github.com/joho/godotenv。

在 config 目录中增加 env.go 文件,输入如下内容:

复制package config import ( "log" "os" "github.com/joho/godotenv" ) func EnvMongoURI() string { err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } return os.Getenv("MONGOURI") } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.

然后执行 go mod tidy,更新依赖。(这个命令可以多次执行)

连接到 MongoDB

接着在 config 目录下创建 setup.go 文件,增加如下内容:

复制package config import ( "context" "fmt" "log" "time" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func ConnectDB() *mongo.Client { client, err := mongo.NewClient(options.Client().ApplyURI(EnvMongoURI())) if err != nil { log.Fatal(err) } ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) err = client.Connect(ctx) if err != nil { log.Fatal(err) } // ping the database err = client.Ping(ctx, nil) if err != nil { log.Fatal(err) } fmt.Println("Connected to MongoDB") return client } // MongoDB 客户端实例 var DB *mongo.Client = ConnectDB() // GetCollection 获得数据库集合 func GetCollection(client *mongo.Client, collectionName string) *mongo.Collection { collection := client.Database("golangAPI").Collection(collectionName) return collection } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.

以上代码简单解释下:

导入所需的 MongoDB 依赖创建一个ConnectDB 函数,首先将客户端配置为使用正确的 URI 并检查错误。其次,我们定义了尝试连接时要使用的 10 秒超时。第三,检查连接数据库时是否出错,如果连接时间超过10秒,则取消连接。最后,我们 ping 数据库以测试我们的连接并返回client实例。调用 ConnectDB 创建一个DB变量实例。这在创建集合时会派上用场。创建一个 GetCollection 函数获取 collections。

以上的设计并不是最好的,主要让大家熟悉操作 MongoDB 的 API。

4、设置 API 路由处理程序和响应类型

Route Handler

完成后,我们需要在 route 文件夹中创建一个 user_route.go 文件,管理我们应用程序中所有与用户相关的路由,如下所示:

复制package routes import "github.com/gofiber/fiber/v2" func UserRoute(app *fiber.App) { // All routes related to users comes here } 1.2.3.4.5.6.7.

接下来,修改 main.go,路由交给上面的函数处理:

复制package main import ( "github.com/gofiber/fiber/v2" "github.com/programmerug/fibermongo/route" ) func main() { app := fiber.New() // routes route.UserRoute(app) app.Listen(":2022") } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.

响应类型

接下来,我们需要创建一个可重用的 struct 的来描述我们 API 的响应。为此,在 response 文件夹创建一个user_response.go文件并添加以下内容:

复制package response import "github.com/gofiber/fiber/v2" type UserResponse struct { Status int `json:"status"` Message string `json:"message"` Data interface{} `json:"data"` } 1.2.3.4.5.6.7.8.9.

上面的代码片段创建了一个通用的响应类型:UserResponse。

5、REST API

接下来,我们需要一个 model 来表示我们的应用程序数据。

为此,我们在 model 中创建 user_model.go 文件并输入如下内容:

复制package model import "go.mongodb.org/mongo-driver/bson/primitive" type User struct { ID primitive.ObjectID `json:"id,omitempty"` Name string `json:"name,omitempty" validate:"required"` Location string `json:"location,omitempty" validate:"required"` Title string `json:"title,omitempty" validate:"required"` } 1.2.3.4.5.6.7.8.9.10.

要解释的是上面的 tag:validate,这是 github.com/go-playground/validator/v10 库。

创建 User 端点

有了 model,我们现在可以创建一个函数来创建用户。

在 controller 文件夹下创建文件 user_controller.go 并添加以下内容:

复制package controller import ( "context" "net/http" "time" "github.com/programmerug/fibermongo/config" "github.com/programmerug/fibermongo/model" "github.com/programmerug/fibermongo/response" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" ) var userCollection *mongo.Collection = config.GetCollection(config.DB, "user") var validate = validator.New() func CreateUser(c *fiber.Ctx) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) var user model.User defer cancel() // validate the request body if err := c.BodyParser(&user); err != nil { return c.Status(http.StatusBadRequest).JSON(response.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &fiber.Map{"data": err.Error()}}) } // use the validator library to validate required fields if validationErr := validate.Struct(&user); validationErr != nil { return c.Status(http.StatusBadRequest).JSON(response.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &fiber.Map{"data": validationErr.Error()}}) } newUser := model.User{ ID: primitive.NewObjectID(), Name: user.Name, Location: user.Location, Title: user.Title, } result, err := userCollection.InsertOne(ctx, newUser) if err != nil { return c.Status(http.StatusInternalServerError).JSON(response.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()}) } return c.Status(http.StatusCreated).JSON(response.UserResponse{Status: http.StatusCreated, Message: "success", Data: result}) } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.

这段代码比较多,简单解释下:

首先导入了相关的依赖通过 config 中的 GetCollection 函数创建 userCollection通过 github.com/go-playground/validator/v10 获得 validater 校验器在 CreateUser 函数中,我们首先定义了将用户插入文档时的 10 秒超时,使用验证器库验证请求正文和必填字段。如果有错误,包装成 UserResponse 返回了适当的消息和状态代码。其次,我们创建了一个newUser变量,使用userCollection.InsertOne 函数将其插入并检查是否有错误。最后,如果插入成功,我们会返回正确的响应。

接着在 user_route.go 文件中绑定 API URL 和对应的 handler:

复制package route import ( "github.com/gofiber/fiber/v2" "github.com/programmerug/fibermongo/controller" ) func UserRoute(app *fiber.App) { app.Post("/user", controller.CreateUser) } 1.2.3.4.5.6.7.8.9.10.

go run main.go 启动程序,不出意外会看到如下输出:

复制$ go run main.go Connected to MongoDB ┌───────────────────────────────────────────────────┐ │ Fiber v2.26.0 │ │ http://127.0.0.1:2022 │ │ (bound on host 0.0.0.0 and port 2022) │ │ │ │ Handlers ............. 1 Processes ........... 1 │ │ Prefork ....... Disabled PID .............. 7158 │ └───────────────────────────────────────────────────┘ 1.2.3.4.5.6.7.8.9.10.11.

然后通过 curlie 测试创建用户:

复制$ curlie POST -d { "name": "幽鬼", "location": "北京", "title": "Software Engineer" } http://localhost:2022/user 1.2.3.4.5.

会看到如下输出:

复制HTTP/1.1 201 Created Date: Tue, 08 Feb 2022 03:08:17 GMT Content-Type: application/json Content-Length: 92 { "status": 201, "message": "success", "data": { "InsertedID": "6201de338ecf6d62fb799d62" } } 1.2.3.4.5.6.7.8.9.10.11.12.

然后你可以到 MongoDB 确认,数据有没有写入:

insert one

其他操作

接下来就是实现查找、更新和删除。这块内容不一一细讲,只列出关键代码。

先看完整的路由:

复制package route import ( "github.com/gofiber/fiber/v2" "github.com/programmerug/fibermongo/controller" ) func UserRoute(app *fiber.App) { app.Post("/user", controller.CreateUser) app.Get("/user/:userId", controller.GetAUser) app.Put("/user/:userId", controller.EditAUser) app.Delete("/user/:userId", controller.DeleteAUser) app.Get("/users", controller.GetAllUsers) } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.

通过 userId 获取用户信息中,因为 userId 是字符串,需要转为 BSON 的 objectID。MongoDB 库有一个专门的函数:

复制objId, _ := primitive.ObjectIDFromHex(userId) 1.

具体的操作 MongoDB 的 API 可以查阅文档:https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo。

6、结论

本文主要在于带着大家完成一个基本的 CRUD 工作,让大家熟悉 Fiber + MongoDB 构建 RESTful API,熟悉工作流程。同时了解相关库的使用。

本文的完整代码见:https://github.com/programmerug/fibermongo。

参考文章:https://dev.to/hackmamba/build-a-rest-api-with-golang-and-mongodb-fiber-version-4la0

此外,测试 API 时,大家可以使用自己喜欢的工具,比如 postman。

参考资料

[1]curlie: https://curlie.io/

本文转载自微信公众号「幽鬼」,可以通过以下二维码关注。转载本文请联系幽鬼公众号。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:反欺诈(羊毛盾)API有什么作用?
下一篇:快递物流查询API有什么作用?
相关文章

 发表评论

暂时没有评论,来抢沙发吧~