所有文章 > API开发 > 使用Golang和MongoDB构建REST API- Echo版本

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

封面照片

表述性状态传输(REST)是一种架构模式,用于指导应用程序编程接口(API)的设计和开发。REST API 已成为产品服务器端与其客户端之间通信的标准,旨在提升性能、可伸缩性、简单性、可修改性、可见性、可移植性和可靠性。

本文将探讨如何使用 Echo 框架和 MongoDB,通过 Golang 来构建一个用户管理应用程序。在本教程的结尾,您将学会如何构建 Echo 应用程序、开发 REST API 以及利用 MongoDB 实现数据的持久化存储。

Echo 是一个高性能且可扩展的 HTTP Web 框架,基于 Golang 开发。它提供了优化的路由、中间件、模板、数据绑定和渲染等功能。

MongoDB 是一种基于文档的数据库管理程序,用作关系数据库的替代方案。MongoDB 支持处理大量分布式数据,并可选择无缝存储或检索信息。

先决条件

本文中的后续步骤要求您具备一定的 Golang 使用经验。虽然拥有 MongoDB 的使用经验会有所帮助,但并非必要条件。

此外,您还需要准备以下内容:

  • 一个用于托管数据库的 MongoDB 帐户。注册该服务是完全免费的。
  • Postman 或您偏好的其他 API 测试工具。

让我们编码

开始

首先,我们需要导航到所需的目录并在我们的终端中运行以下命令:

mkdir echo-mongo-api && cd echo-mongo-api

这条命令用于创建一个文件夹并进入项目目录,该目录名为 echo-mongo-api

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

go mod init echo-mongo-api

这条命令会创建一个文件,用于追踪项目的依赖关系,文件名为 go.mod

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

go get -u github.com/labstack/echo/v4 go.mongodb.org/mongo-driver/mongo github.com/joho/godotenv github.com/go-playground/validator/v10

github.com/labstack/echo/v4 是一个用于构建 Web 应用程序的框架。

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

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

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

应用程序入口点

安装项目依赖项后,我们需要在根目录main.go中创建文件并添加以下代码段:

package main

import (
"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

e.GET("/", func(c echo.Context) error {
return c.JSON(200, &echo.Map{"data": "Hello from Echo & mongoDB"})
})

e.Logger.Fatal(e.Start(":6000"))
}

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

  • 导入所需的依赖项。
  • 使用 echo.New 函数初始化了一个 Echo 应用程序。
  • 使用一个函数来设置路由,将某个路径映射到一个处理器函数,该处理器函数返回一个 JSON 响应。
  • 使用该函数在端口 6000 上运行应用程序。

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

Golang 中的模块化

为我们的项目建立一个良好的文件夹结构至关重要。良好的项目结构能够简化我们在应用程序中处理依赖关系的方式,并且使得我们自己和其他人更容易阅读代码库。

为此,我们需要在项目目录中创建以下文件夹:configscontrollersmodelsresponses 和 routes

PS: 该文件包含所有依赖项校验并由 go 工具管理。我们不必担心。

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

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

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

responses 用于模块化文件,描述我们希望 API 给出的响应。这在后面会变得更加清楚。

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

设置 MongoDB

完成后,我们需要登录或注册我们的 MongoDB 帐户。单击项目下拉菜单,然后单击 New Project 按钮。

输入 作为项目名称,单击 Next,然后单击 Create Project。

单击 Build a Database(构建数据库

选择 Shared (共享) 作为数据库的类型。

单击 Create 以设置集群。这可能需要一些时间来设置。

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

保存更改后,我们应该会看到 Database Deployments 屏幕,如下所示:

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

完成配置后,我们需要将应用程序与创建的数据库连接起来。为此,请单击 Connect 按钮

单击 Connect your application 更改Driver 和Version ,如下所示。然后单击复制图标以复制连接字符串。

Setup 环境变量

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

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

下面正确填充的连接字符串示例:

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

加载环境变量

完成上述步骤后,我们需要创建一个辅助函数,利用之前安装的库来加载环境变量。为此,我们需要导航到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")
}

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

  • 导入所需的依赖项。
  • 创建了一个函数,该函数检查环境变量是否正确加载,并返回名为 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
}

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

  • 导入所需的依赖项。
  • 创建了一个名为 ConnectDB 的函数,该函数首先配置客户端以使用正确的URI,并检查是否出现错误。其次,我们定义了10秒的连接超时时间。再次,该函数会检查连接数据库时是否出现错误,如果连接时间超过10秒,则取消连接。最后,该函数会向数据库发送ping请求以测试连接,并返回客户端实例。
  • 创建一个名为 DBConnectDB 的变量实例,这个实例在创建集合时会非常有用。
  • 创建一个名为 GetCollection 的函数,用于从数据库中检索或创建集合。

接下来,我们需要在应用程序启动时连接到数据库。为此,我们需要修改如下:

package main

import (
"echo-mongo-api/configs" //add this
"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

//run database
configs.ConnectDB()

e.Logger.Fatal(e.Start(":6000"))
}

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

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

package routes

import "github.com/labstack/echo/v4"

func UserRoute(e *echo.Echo) {
//All routes related to users comes here
}

接下来,我们需要将新创建的路由附加到 http.服务器,修改如下所示:

package main

import (
"echo-mongo-api/configs"
"echo-mongo-api/routes" //add this

"github.com/labstack/echo/v4"
)

func main() {
e := echo.New()

//run database
configs.ConnectDB()

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

e.Logger.Fatal(e.Start(":6000"))
}

响应类型

接下来,我们需要创建一个可复用的结构体来描述API的响应。为此,请导航到user_response.go文件夹,并在该文件夹中创建一个文件,然后添加以下代码段:

package responses

import (
"github.com/labstack/echo/v4"
)

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

上面的描述创建了一个结构体,该结构体包含 StatusMessage 和 Data 属性,以表示API的响应类型。

这里,UserResponse 是结构体的名称,而 StatusMessage 和 Data 是其属性。json:”status”json:”message” 和 json:”data” 是所谓的结构体标签(struct tags),它们允许我们为相应的结构体属性附加元信息。换句话说,我们使用这些标签来重新格式化API返回的JSON响应中的字段名。

最后创建 REST API

接下来,我们需要一个模型来表示我们的应用程序数据。为此,我们需要导航到该文件夹,并在此文件夹中创建modelsuser_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"`
}

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

  • 导入所需的依赖项。
  • 创建具有所需属性的结构。我们在 struct 标签中添加库告诉 Fiber 忽略空字段并将字段设为 required。

创建用户终端节点
通过模型设置,我们现在可以创建一个函数来创建用户。为此,我们需要导航到该文件夹,并在此文件夹中创建一个文件并添加下面的代码段:

package controllers

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

"github.com/go-playground/validator/v10"
"github.com/labstack/echo/v4"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"golang.org/x/net/context"
)

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

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

//validate the request body
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

//use the validator library to validate required fields
if validationErr := validate.Struct(&user); validationErr != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

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

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

  • 导入所需的依赖项。
  • 创建了 userCollection 和 validate 变量,分别用于创建集合和使用之前安装的库来验证模型。这里提到的库是 github.com/go-playground/validator/v10
  • 创建返回错误的函数。在函数内部,我们首先定义了 10 秒的超时时间,当 user 插入到文档中时,使用验证器库验证请求正文和必填字段。我们使用之前创建的结构返回了相应的消息和状态代码。其次,我们创建了一个变量,使用函数插入它,并检查是否有错误。最后,如果插入成功,我们返回正确的响应。

接下来,我们需要使用路由 API URL 和相应的控制器进行更新,如下所示:

package routes

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

"github.com/labstack/echo/v4"
)

func UserRoute(e *echo.Echo) {
e.POST("/user", controllers.CreateUser) //add this
}

获取用户终端节点
要获取用户的详细信息,我们需要修改如下:

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 echo.Context) error {
//create user code goes here
}

func GetAUser(c echo.Context) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
userId := c.Param("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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

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

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

  • 导入所需的依赖项。
  • 创建返回错误的函数。在该函数中,我们首先定义了在文档中查找用户时 10 秒的超时时间、用于从 URL 参数获取用户 ID 的 userId 变量以及 user 变量。我们将将userId从字符串类型转换为MongoDB使用的BSON类型primitive.ObjectID。使用userCollection.FindOne方法搜索用户,将转换后的objId作为过滤器传递,并使用attribute 方法来获取相应的用户对象。最后,我们返回解码后的响应。

接下来,我们需要使用路由 API URL 和相应的控制器进行更新,如下所示:

package routes

import (
//import goes here
)

func UserRoute(e *echo.Echo) {
//other routes goes here
e.GET("/user/:userId", controllers.GetAUser) //add this
}

PS: 我们还向URL路径传递了一个userid参数。这个指定的参数必须与我们在控制器中指定的参数相匹配。

编辑用户端点

为了编辑用户,我们需要按照下面的方式修改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 echo.Context) error {
//create user code goes here
}

func GetAUser(c echo.Context) error {
//get a user code goes here
}

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

objId, _ := primitive.ObjectIDFromHex(userId)

//validate the request body
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

//use the validator library to validate required fields
if validationErr := validate.Struct(&user); validationErr != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}
}

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

上述函数与CreateUser函数的功能类似,但有所不同。在这个函数中,我们引入了一个update变量,用于获取需要更新的字段,并使用.UpdateOne方法更新了集合中的记录。最后,我们搜索了更新后的用户详情,并返回了解码后的响应。

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

package routes

import (
//import goes here
)

func UserRoute(e *echo.Echo) {
//other routes goes here
e.PUT("/user/:userId", controllers.EditAUser) //add this
}

删除用户终端节点

要删除一个用户,我们需要修改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 echo.Context) error {
//create user code goes here
}

func GetAUser(c echo.Context) error {
//get a user code goes here
}

func EditAUser(c echo.Context) error {
//edit a user code goes here
}

func DeleteAUser(c echo.Context) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
userId := c.Param("userId")
defer cancel()

objId, _ := primitive.ObjectIDFromHex(userId)

result, err := userCollection.DeleteOne(ctx, bson.M{"id": objId})

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

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

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

该函数按照前面的步骤操作,我们还检查了项目是否已成功删除并返回相应的响应。

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

package routes

import (
//import goes here
)

func UserRoute(e *echo.Echo) {
//other routes goes here
e.DELETE("/user/:userId", controllers.DeleteAUser) //add this
}

获取用户列表端点
要获取用户列表,我们需要修改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 echo.Context) error {
//create user code goes here
}

func GetAUser(c echo.Context) error {
//get a user code goes here
}

func EditAUser(c echo.Context) error {
//edit a user code goes here
}

func DeleteAUser(c echo.Context) error {
//delete a user code goes here
}

func GetAllUsers(c echo.Context) 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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

users = append(users, singleUser)
}

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

该函数按照前面的步骤操作,我们还使用 attribute 方法以最佳方式读取 retuned 列表,以遍历返回的用户列表。

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

package routes

import (
//import goes here
)

func UserRoute(e *echo.Echo) {
//other routes goes here
e.GET("/users", controllers.GetAllUsers) //add this
}

user_controller.go

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

"github.com/go-playground/validator/v10"
"github.com/labstack/echo/v4"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"golang.org/x/net/context"
)

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

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

//validate the request body
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

//use the validator library to validate required fields
if validationErr := validate.Struct(&user); validationErr != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

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

func GetAUser(c echo.Context) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
userId := c.Param("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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

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

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

objId, _ := primitive.ObjectIDFromHex(userId)

//validate the request body
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

//use the validator library to validate required fields
if validationErr := validate.Struct(&user); validationErr != nil {
return c.JSON(http.StatusBadRequest, responses.UserResponse{Status: http.StatusBadRequest, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}
}

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

func DeleteAUser(c echo.Context) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
userId := c.Param("userId")
defer cancel()

objId, _ := primitive.ObjectIDFromHex(userId)

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

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

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

func GetAllUsers(c echo.Context) 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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.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.JSON(http.StatusInternalServerError, responses.UserResponse{Status: http.StatusInternalServerError, Message: "error", Data: &echo.Map{"data": err.Error()}})
}

users = append(users, singleUser)
}

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

user_route.go

package routes

import (
"echo-mongo-api/controllers"
"github.com/labstack/echo/v4"
)

func UserRoute(e *echo.Echo) {
e.POST("/user", controllers.CreateUser)
e.GET("/user/:userId", controllers.GetAUser)
e.PUT("/user/:userId", controllers.EditAUser)
e.DELETE("/user/:userId", controllers.DeleteAUser)
e.GET("/users", controllers.GetAllUsers)
}

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

go run main.go

结论

本文探讨了如何利用 MongoDB 构建 Echo 应用程序、开发 REST API 以及实现数据的持久化保存。

您可能会发现以下资源对您有所帮助:

  • Echo 框架
  • MongoDB Go 驱动程序
  • Go 验证器
  • Go 环境加载程序

原文链接:https://medium.com/geekculture/build-a-rest-api-with-golang-and-mongodb-echo-version-be48eccdefe3