发布于 2026-01-06 3 阅读
0

使用 Golang 和 MongoDB 构建 REST API - Fiber 版本要求 开始编码 结论

使用 Golang 和 MongoDB 构建 REST API - Fiber 版本

先决条件

让我们开始编程吧

结论

表述性状态转移(REST)是一种架构模式,它指导应用程序编程接口(API)的设计和开发。REST API 已成为产品服务器端与其客户端之间通信的标准,以提高性能、可扩展性、简洁性、可修改性、可见性、可移植性和可靠性。

本文将探讨如何使用 Golang、Fiber框架和MongoDB构建用户管理应用程序。在本教程的最后,我们将学习如何构建 Fiber 应用程序、创建 REST API 以及使用 MongoDB 持久化数据。

Fiber 是一个受Express启发、用 Golang 编写的 HTTP Web 框架,它具有高性能和零内存分配支持。Fiber 构建于Fasthttp之上,Fasthttp 本身也是一个用 Golang 编写的 HTTP 引擎。

MongoDB 是一款基于文档的数据库管理程序,可作为关系型数据库的替代方案。MongoDB 支持处理大型分布式数据集,并提供无缝存储和检索信息的选项。

您可以在此存储库中找到完整的源代码

先决条件

本文后续步骤需要具备 Golang 编程经验。虽然不要求具备 MongoDB 经验,但有相关经验会更好。

我们还需要以下物品:

让我们开始编程吧

入门

首先,我们需要导航到目标目录,然后在终端中运行以下命令。

mkdir fiber-mongo-api && cd fiber-mongo-api
Enter fullscreen mode Exit fullscreen mode

该命令会创建一个fiber-mongo-api文件夹并导航到项目目录。

接下来,我们需要初始化一个 Go 模块来管理项目依赖项,运行以下命令:

go mod init fiber-mongo-api
Enter fullscreen mode Exit fullscreen mode

此命令将创建一个go.mod用于跟踪项目依赖关系的文件。

接下来,我们使用以下命令安装所需的依赖项:

go get -u github.com/gofiber/fiber/v2 go.mongodb.org/mongo-driver/mongo github.com/joho/godotenv github.com/go-playground/validator/v10
Enter fullscreen mode Exit fullscreen mode

github.com/gofiber/fiber/v2是一个用于构建 Web 应用程序的框架。

go.mongodb.org/mongo-driver/mongo是用于连接 MongoDB 的驱动程序。

github.com/joho/godotenv是一个用于管理环境变量的库。

github.com/go-playground/validator/v10是一个用于验证结构体和字段的库。

github.com/klauspost/compress is not in your go.mod filego mod tidy安装完所需的依赖项后,文件中可能会出现错误go.mod。要解决此问题,我们需要手动安装所需的软件包。

go get github.com/klauspost/compress
Enter fullscreen mode Exit fullscreen mode

应用程序入口点

项目依赖项安装完毕后,我们需要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{"data": "Hello from Fiber & mongoDB"})
    })

    app.Listen(":6000")
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段执行以下操作:

  • 导入所需的依赖项。
  • 使用该函数初始化 Fiber 应用程序New
  • 使用该Get函数路由到/路径和返回 JSON 的处理函数Hello from Fiber & mongoDBfiber.Map是的快捷方式map[string]interface{},对 JSON 返回很有用。
  • 设置应用程序监听端口6000

接下来,我们可以通过在终端中运行以下命令来启动开发服务器,从而测试我们的应用程序。

go run main.go
Enter fullscreen mode Exit fullscreen mode

测试应用

Golang 中的模块化

良好的项目文件夹结构至关重要。合理的项目结构可以简化我们管理应用程序依赖项的方式,并使我们自己和其他人更容易阅读代码库。
为此,我们需要在项目目录中创建 `<module> configs`、 `<module> ` controllers、 `<module> ` 和`<module>` 文件夹。modelsresponsesroutes

更新了项目文件夹结构

PS go.sum 文件包含所有依赖项校验和,并由 go 工具自动管理,我们无需担心。

configs用于模块化项目配置文件

controllers是用于模块化应用程序逻辑。

models是用于数据和数据库逻辑的模块化。

responses是用来模块化描述我们希望 API 返回的响应的文件。这一点稍后会更清楚。

routes用于模块化 URL 模式和处理程序信息。

设置 MongoDB

完成上述步骤后,我们需要登录或注册MongoDB帐户。​​点击项目下拉菜单,然后点击“新建项目”按钮。

新项目

输入golang-api项目名称,点击“下一步”,然后点击“创建项目”。

输入项目名称
创建项目

点击“构建数据库”

选择“共享”作为数据库类型。

共享内容以红色高亮显示

点击“创建”按钮设置集群。设置过程可能需要一些时间。

创建集群

接下来,我们需要创建一个用户,以便从外部访问数据库。输入用户名密码,然后点击“创建用户”。我们还需要添加自己的 IP 地址,以便安全地连接到数据库。点击“添加我的当前 IP 地址”按钮即可。然后点击“完成并关闭”保存更改。

创建用户
添加 IP

保存更改后,应该会看到如下所示的“数据库部署”屏幕:

数据库屏幕

将我们的应用程序连接到 MongoDB

配置完成后,我们需要将应用程序连接到已创建的数据库。为此,请单击“连接”按钮。

连接到数据库

点击“连接您的应用程序”,将驱动程序Go版本更改为如下所示的内容。然后点击复制图标复制连接字符串。

连接应用程序
复制连接字符串

设置环境变量
接下来,我们需要修改复制的连接字符串,使其包含我们之前创建的用户密码,并更改数据库名称。为此,首先需要.env在根目录下创建一个文件,并在该文件中添加以下代码片段:

MONGOURI=mongodb+srv://<YOUR USERNAME HERE>:<YOUR PASSWORD HERE>@cluster0.e5akf.mongodb.net/myFirstDatabese?retryWrites=true&w=majority
Enter fullscreen mode Exit fullscreen mode

以下是一个正确填写的连接字符串示例:

MONGOURI=mongodb+srv://malomz:malomzPassword@cluster0.e5akf.mongodb.net/golangDB?retryWrites=true&w=majority
Enter fullscreen mode Exit fullscreen mode

更新了包含 .env 文件的文件夹结构

加载环境变量
完成上述步骤后,我们需要创建一个辅助函数,使用github.com/joho/godotenv之前安装的库来加载环境变量。为此,我们需要导航到该configs文件夹​​,并在该文件夹中创建一个env.go文件,然后添加以下代码片段:



package configs

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")
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段执行以下操作:

  • 导入所需的依赖项。
  • 创建一个EnvMongoURI函数,检查环境变量是否已正确加载,并返回该环境变量。

连接到 MongoDB
要从我们的应用程序连接到 MongoDB 数据库,首先需要导航到该configs文件夹​​,并在该文件夹中创建一个setup.go文件,然后添加以下代码片段:



package configs

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
}

//Client instance
var DB *mongo.Client = ConnectDB()

//getting database collections
func GetCollection(client *mongo.Client, collectionName string) *mongo.Collection {
    collection := client.Database("golangAPI").Collection(collectionName)
    return collection
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段执行以下操作:

  • 导入所需的依赖项。
  • 创建一个ConnectDB函数,首先配置客户端使用正确的 URI 并检查错误。其次,我们定义了一个 10 秒的连接超时时间。第三,检查连接数据库时是否存在错误,如果连接时间超过 10 秒则取消连接。最后,我们 ping 了数据库以测试连接,并返回了实例client
  • 创建一个DB变量实例ConnectDB。这在创建集合时会非常有用。
  • 创建一个函数,用于在数据库中GetCollection检索和创建数据。collections

接下来,我们需要在应用程序启动时连接到数据库。为此,我们需要main.go按如下所示进行修改:



package main

import (
    "fiber-mongo-api/configs" //add this
    "github.com/gofiber/fiber/v2" 
)

func main() {
    app := fiber.New()

    //run database
    configs.ConnectDB()

    app.Listen(":6000")
}


Enter fullscreen mode Exit fullscreen mode

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

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



package routes

import "github.com/gofiber/fiber/v2"

func UserRoute(app *fiber.App) {
    //All routes related to users comes here
}


Enter fullscreen mode Exit fullscreen mode

接下来,我们需要将新创建的路由附加到http.Server,具体main.go操作如下所示:



package main

import (
    "fiber-mongo-api/configs"
    "fiber-mongo-api/routes" //add this
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()

    //run database
    configs.ConnectDB()

    //routes
    routes.UserRoute(app) //add this

    app.Listen(":6000")
}


Enter fullscreen mode Exit fullscreen mode


接下来,我们需要创建一个可重用的响应类型描述struct符来描述 API 的响应。为此,请导航到该responses文件夹​​,并在其中创建一个user_response.go文件,然后添加以下代码片段:



package responses

import "github.com/gofiber/fiber/v2"

type UserResponse struct {
    Status  int        `json:"status"`
    Message string     `json:"message"`
    Data    *fiber.Map `json:"data"`
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段创建了一个UserResponse包含`<struct>` StatusMessage`<property>` 和Data`<property>` 属性的结构体,用于表示 API 响应类型。

PSjson:"status"`<string>`、 json:"message"`<string>` 和 `<string>` json:"data" 被称为 结构体标签。结构体标签允许我们将元信息附加到相应的结构体属性上。换句话说,我们使用它们来重新格式化 API 返回的 JSON 响应。

最后,创建 REST API

接下来,我们需要一个模型来表示我们的应用程序数据。为此,我们需要导航到该models文件夹​​,并在该文件夹中创建一个user_model.go文件,然后添加以下代码片段:



package models

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"`
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段执行以下操作:

  • 导入所需的依赖项。
  • 创建一个User包含必需属性的结构体。我们在结构体标签中添加了 `--no-text`omitemptyvalidate:"required"`--no-text`,分别告诉 Fiber 忽略空字段并将该字段设为必需字段。

创建用户端点
模型设置完成后,我们现在可以创建一个创建用户的函数。为此,我们需要导航到该controllers文件夹​​,并在该文件夹中创建一个user_controller.go文件,然后添加以下代码片段:



package controllers

import (
    "context"
    "fiber-mongo-api/configs"
    "fiber-mongo-api/models"
    "fiber-mongo-api/responses"
    "net/http"
    "time"

    "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 = configs.GetCollection(configs.DB, "users")
var validate = validator.New()

func CreateUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    var user models.User
    defer cancel()

    //validate the request body
    if err := c.BodyParser(&user); err != nil {
        return c.Status(http.StatusBadRequest).JSON(responses.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(responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &fiber.Map{"data": validationErr.Error()}})
    }

    newUser := models.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(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    return c.Status(http.StatusCreated).JSON(responses.UserResponse{Status: http.StatusCreated, Message: "success", Data: &fiber.Map{"data": result}})
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段执行以下操作:

  • 导入所需的依赖项。
  • 分别使用我们之前安装的库创建集合和验证模型的变量userCollectionvalidategithub.com/go-playground/validator/v10
  • 创建一个CreateUser返回值的函数error。在函数内部,我们首先定义了向文档插入用户时 10 秒的超时时间,并使用验证器库验证请求体和必填字段。我们使用UserResponse之前创建的结构体返回相应的消息和状态码。其次,我们创建了一个newUser变量,使用该函数插入它userCollection.InsertOne,并检查是否存在错误。最后,如果插入成功,我们返回正确的响应。

接下来,我们需要更新user_routes.go路由 API URL 和相应的控制器,如下所示:



package routes

import (
    "fiber-mongo-api/controllers" //add this

    "github.com/gofiber/fiber/v2"
)

func UserRoute(app *fiber.App) {
    app.Post("/user", controllers.CreateUser) //add this
}


Enter fullscreen mode Exit fullscreen mode

获取用户端点
要获取用户详细信息,我们需要user_controller.go按如下所示进行修改:



package controllers

import (
    //other import goes here    
    "go.mongodb.org/mongo-driver/bson" //add this
)

var userCollection *mongo.Collection = configs.GetCollection(configs.DB, "users")
var validate = validator.New()

func CreateUser(c *fiber.Ctx) error {
    //create user code goes here
}

func GetAUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    userId := c.Params("userId")
    var user models.User
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    err := userCollection.FindOne(ctx, bson.M{"id": objId}).Decode(&user)
    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    return c.Status(http.StatusOK).JSON(responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": user}})
}


Enter fullscreen mode Exit fullscreen mode

上面的代码片段执行以下操作:

  • 导入所需的依赖项。
  • 创建一个GetAUser返回一个对象的函数error。在函数内部,我们首先定义了在文档中查找用户的超时时间(10 秒),一个用于从 URL 参数中userId获取用户IDuser的变量,以及一个用于将 URL 参数中的字符串转换userIdprimitive.ObjectIDMongoDB 使用的 BSON 类型的变量。其次,我们使用 URL 参数搜索用户userCollection.FindOne,并将 URLobjId作为过滤器传递,然后使用Decode属性方法获取相应的对象。最后,我们返回解码后的响应。

接下来,我们需要更新user_routes.go路由 API URL 和相应的控制器,如下所示:



package routes

import (
    //import goes here
)

func UserRoute(app *fiber.App) {
    //other routes goes here
    app.Get("/user/:userId", controllers.GetAUser) //add this
}


Enter fullscreen mode Exit fullscreen mode

PS: 我们还 userId 向 URL 路径传递了一个参数。该参数必须与我们在控制器中指定的参数一致。

编辑用户端点
要编辑用户,我们需要user_controller.go按如下所示进行修改:



package controllers

import (
    //other import goes here
)

var userCollection *mongo.Collection = configs.GetCollection(configs.DB, "users")
var validate = validator.New()

func CreateUser(c *fiber.Ctx) error {
    //create user code goes here
}

func GetAUser(c *fiber.Ctx) error {
    //get a user code goes here
}

func EditAUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    userId := c.Params("userId")
    var user models.User
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    //validate the request body
    if err := c.BodyParser(&user); err != nil {
        return c.Status(http.StatusBadRequest).JSON(responses.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(responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &fiber.Map{"data": validationErr.Error()}})
    }

    update := bson.M{"name": user.Name, "location": user.Location, "title": user.Title}

    result, err := userCollection.UpdateOne(ctx, bson.M{"id": objId}, bson.M{"$set": update})

    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }
    //get updated user details
    var updatedUser models.User
    if result.MatchedCount == 1 {
        err := userCollection.FindOne(ctx, bson.M{"id": objId}).Decode(&updatedUser)

        if err != nil {
            return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
        }
    }

    return c.Status(http.StatusOK).JSON(responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": updatedUser}})
}


Enter fullscreen mode Exit fullscreen mode

上面的函数EditAUser与原函数功能相同CreateUser。但是,我们添加了一个update变量来获取更新后的字段,并使用该变量更新了集合userCollection.UpdateOne。最后,我们搜索了更新后的用户详细信息,并返回了解码后的响应。

接下来,我们需要更新user_routes.go路由 API URL 和相应的控制器,如下所示:



package routes

import (
    //import goes here
)

func UserRoute(app *fiber.App) {
    //other routes goes here 
    app.Put("/user/:userId", controllers.EditAUser) //add this
}


Enter fullscreen mode Exit fullscreen mode

删除用户端点
要删除用户,我们需要user_controller.go按如下所示进行修改:



package controllers

import (
    //other import goes here
)

var userCollection *mongo.Collection = configs.GetCollection(configs.DB, "users")
var validate = validator.New()

func CreateUser(c *fiber.Ctx) error {
    //create user code goes here
}

func GetAUser(c *fiber.Ctx) error {
    //get a user code goes here
}

func EditAUser(c *fiber.Ctx) error {
    //edit a user code goes here
}

func DeleteAUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    userId := c.Params("userId")
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    result, err := userCollection.DeleteOne(ctx, bson.M{"id": objId})
    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    if result.DeletedCount < 1 {
        return c.Status(http.StatusNotFound).JSON(
            responses.UserResponse{Status: http.StatusNotFound, Message: "error", Data: &fiber.Map{"data": "User with specified ID not found!"}},
        )
    }

    return c.Status(http.StatusOK).JSON(
        responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": "User successfully deleted!"}},
    )
}


Enter fullscreen mode Exit fullscreen mode

DeleteAUser函数遵循之前的步骤,使用删除匹配的记录userCollection.DeleteOne。我们还检查了项目是否已成功删除,并返回了相应的响应。

接下来,我们需要更新user_routes.go路由 API URL 和相应的控制器,如下所示:



package routes

import (
    //import goes here
)

func UserRoute(app *fiber.App) {
    //other routes goes here
    app.Delete("/user/:userId", controllers.DeleteAUser) //add this
}


Enter fullscreen mode Exit fullscreen mode

获取用户列表端点
要获取用户列表,我们需要user_controller.go按如下所示进行修改:



package controllers

import (
    //other import goes here
)

var userCollection *mongo.Collection = configs.GetCollection(configs.DB, "users")
var validate = validator.New()

func CreateUser(c *fiber.Ctx) error {
    //create user code goes here
}

func GetAUser(c *fiber.Ctx) error {
    //get a user code goes here
}

func EditAUser(c *fiber.Ctx) error {
    //edit a user code goes here
}

func DeleteAUser(c *fiber.Ctx) error {
    //delete a user code goes here
}

func GetAllUsers(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    var users []models.User
    defer cancel()

    results, err := userCollection.Find(ctx, bson.M{})

    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    //reading from the db in an optimal way
    defer results.Close(ctx)
    for results.Next(ctx) {
        var singleUser models.User
        if err = results.Decode(&singleUser); err != nil {
            return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
        }

        users = append(users, singleUser)
    }

    return c.Status(http.StatusOK).JSON(
        responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": users}},
    )
}


Enter fullscreen mode Exit fullscreen mode

GetAllUsers函数遵循之前的步骤,通过获取用户列表来实现。我们还使用属性方法遍历返回的用户列表,userCollection.Find从而以最优方式读取该列表。Next

接下来,我们需要更新user_routes.go路由 API URL 和相应的控制器,如下所示:



package routes

import (
    //import goes here
)

func UserRoute(app *fiber.App) {
    //other routes goes here
    app.Get("/users", controllers.GetAllUsers) //add this
}


Enter fullscreen mode Exit fullscreen mode

完成 user_controller.go



package controllers
import (
    "context"
    "fiber-mongo-api/configs"
    "fiber-mongo-api/models"
    "fiber-mongo-api/responses"
    "net/http"
    "time"

    "github.com/go-playground/validator/v10"
    "github.com/gofiber/fiber/v2"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
)

var userCollection *mongo.Collection = configs.GetCollection(configs.DB, "users")
var validate = validator.New()

func CreateUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    var user models.User
    defer cancel()

    //validate the request body
    if err := c.BodyParser(&user); err != nil {
        return c.Status(http.StatusBadRequest).JSON(responses.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(responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &fiber.Map{"data": validationErr.Error()}})
    }

    newUser := models.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(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    return c.Status(http.StatusCreated).JSON(responses.UserResponse{Status: http.StatusCreated, Message: "success", Data: &fiber.Map{"data": result}})
}

func GetAUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    userId := c.Params("userId")
    var user models.User
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    err := userCollection.FindOne(ctx, bson.M{"id": objId}).Decode(&user)
    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    return c.Status(http.StatusOK).JSON(responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": user}})
}

func EditAUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    userId := c.Params("userId")
    var user models.User
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    //validate the request body
    if err := c.BodyParser(&user); err != nil {
        return c.Status(http.StatusBadRequest).JSON(responses.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(responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &fiber.Map{"data": validationErr.Error()}})
    }

    update := bson.M{"name": user.Name, "location": user.Location, "title": user.Title}

    result, err := userCollection.UpdateOne(ctx, bson.M{"id": objId}, bson.M{"$set": update})
    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    //get updated user details
    var updatedUser models.User
    if result.MatchedCount == 1 {
        err := userCollection.FindOne(ctx, bson.M{"id": objId}).Decode(&updatedUser)
        if err != nil {
            return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
        }
    }

    return c.Status(http.StatusOK).JSON(responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": updatedUser}})
}

func DeleteAUser(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    userId := c.Params("userId")
    defer cancel()

    objId, _ := primitive.ObjectIDFromHex(userId)

    result, err := userCollection.DeleteOne(ctx, bson.M{"id": objId})
    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    if result.DeletedCount < 1 {
        return c.Status(http.StatusNotFound).JSON(
            responses.UserResponse{Status: http.StatusNotFound, Message: "error", Data: &fiber.Map{"data": "User with specified ID not found!"}},
        )
    }

    return c.Status(http.StatusOK).JSON(
        responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": "User successfully deleted!"}},
    )
}

func GetAllUsers(c *fiber.Ctx) error {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    var users []models.User
    defer cancel()

    results, err := userCollection.Find(ctx, bson.M{})

    if err != nil {
        return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
    }

    //reading from the db in an optimal way
    defer results.Close(ctx)
    for results.Next(ctx) {
        var singleUser models.User
        if err = results.Decode(&singleUser); err != nil {
            return c.Status(http.StatusInternalServerError).JSON(responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &fiber.Map{"data": err.Error()}})
        }

        users = append(users, singleUser)
    }

    return c.Status(http.StatusOK).JSON(
        responses.UserResponse{Status: http.StatusOK, Message: "success", Data: &fiber.Map{"data": users}},
    )
}


Enter fullscreen mode Exit fullscreen mode

完成 user_route.go



package routes

import (
    "fiber-mongo-api/controllers"
    "github.com/gofiber/fiber/v2"
)

func UserRoute(app *fiber.App) {
    app.Post("/user", controllers.CreateUser)
    app.Get("/user/:userId", controllers.GetAUser)
    app.Put("/user/:userId", controllers.EditAUser)
    app.Delete("/user/:userId", controllers.DeleteAUser)
    app.Get("/users", controllers.GetAllUsers)
}


Enter fullscreen mode Exit fullscreen mode

完成上述步骤后,我们可以通过在终端中运行以下命令来启动开发服务器,从而测试我们的应用程序。

go run main.go
Enter fullscreen mode Exit fullscreen mode

终端输出

创建用户端点

获取用户端点

编辑用户端点

删除用户端点

获取用户列表端点

包含用户文档的数据库

结论

本文讨论了如何构建 Fiber 应用程序、构建 REST API 以及使用 MongoDB 持久化数据。

您可能会发现以下资源很有用:

文章来源:https://dev.to/hackmamba/build-a-rest-api-with-golang-and-mongodb-fibre-version-4la0