天天看點

Go 實作restful接口CRUD操作範例(go+gin+mongo)

作者:irics
Go 實作restful接口CRUD操作範例(go+gin+mongo)

Go 實作restful接口CRUD操作範例(go+gin+mongo)

以下是使用Gin和MongoDB實作RESTful API CRUD操作的示例代碼。

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "strconv"

    "github.com/gin-gonic/gin"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/bson/primitive"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

type Book struct {
    ID     primitive.ObjectID `json:"id" bson:"_id,omitempty"`
    Title  string             `json:"title" bson:"title"`
    Author string             `json:"author" bson:"author"`
}

var collection *mongo.Collection

func main() {
    // Connect to MongoDB
    clientOptions := options.Client().ApplyURI("mongodb://192.168.6.145:27017")
    client, err := mongo.Connect(context.Background(), clientOptions)
    if err != nil {
        log.Fatal(err)
    }

    // Check the connection
    err = client.Ping(context.Background(), nil)
    if err != nil {
        log.Fatal(err)
    }

    collection = client.Database("books").Collection("books")

    // Create a Gin router
    router := gin.Default()

    // Define book routes group
    bookRoutes := router.Group("/v1/books")
    {
        bookRoutes.GET("", getBooks)
        bookRoutes.GET("/:id", getBook)
        bookRoutes.POST("", createBook)
        bookRoutes.PUT("/:id", updateBook)
        bookRoutes.DELETE("/:id", deleteBook)
    }

    // Start the server
    router.Run(":8080")
}

func getBooks(c *gin.Context) {
    // Find all books
    cursor, err := collection.Find(context.Background(), bson.M{})
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get books"})
        return
    }

    var books []Book
    if err := cursor.All(context.Background(), &books); err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get books"})
        return
    }

    c.JSON(http.StatusOK, books)
}

func getBook(c *gin.Context) {
    // Get the book ID from the URL parameters
    id, err := primitive.ObjectIDFromHex(c.Param("id"))
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid book ID"})
        return
    }

    // Find the book by ID
    var book Book
    err = collection.FindOne(context.Background(), bson.M{"_id": id}).Decode(&book)
    if err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Book not found"})
        return
    }

    c.JSON(http.StatusOK, book)
}

func createBook(c *gin.Context) {
    // Bind the JSON request body to a Book object
    var book Book
    if err := c.BindJSON(&book); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse request body"})
        return
    }

    // Insert the book into the database
    result, err := collection.InsertOne(context.Background(), book)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create book"})
        return
    }

    // Set the book ID
    book.ID = result.InsertedID.(primitive.ObjectID)

    c.JSON(http.StatusCreated, book)
}

func updateBook(c *gin.Context) { 
 // Get the book ID from the URL parameters 
 id, err := primitive.ObjectIDFromHex(c.Param("id"))
 if err != nil { 
  c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid book ID"}) 
  return  
 }
 // Bind the JSON request body to a Book object
 var book Book
 if err := c.BindJSON(&book); err != nil {
     c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse request body"})
     return
 }

 // Set the book ID
 book.ID = id

 // Update the book in the database
 result, err := collection.ReplaceOne(context.Background(), bson.M{"_id": id}, book)
 if err != nil {
     c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update book"})
     return
 }

 if result.MatchedCount == 0 {
     c.JSON(http.StatusNotFound, gin.H{"error": "Book not found"})
     return
 }

 c.JSON(http.StatusOK, book) 
}
func deleteBook(c *gin.Context) { 
 // Get the book ID from the URL parameters 
 id, err := primitive.ObjectIDFromHex(c.Param("id")) 
 if err != nil { 
  c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid book ID"}) 
  return 
 }
 // Delete the book from the database
 result, err := collection.DeleteOne(context.Background(), bson.M{"_id": id})
 if err != nil {
     c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete book"})
     return
 }

 if result.DeletedCount == 0 {
     c.JSON(http.StatusNotFound, gin.H{"error": "Book not found"})
     return
 }

 c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Book with ID %s has been deleted", id.Hex())})
}
           

以下代碼注解:

在這個代碼中,使用 Golang + Gin + MongoDB 實作了一個簡單的 RESTful API,用于管理書籍資訊。以下是代碼的主要部分注釋解釋:

  • 導入所需的包,包括 "fmt"、"net/http"、"github.com/gin-gonic/gin"、"go.mongodb.org/mongo-driver/bson" 和 "go.mongodb.org/mongo-driver/mongo"。
  • 定義了一個 Book 結構體,使用 bson 标簽将結構體字段映射到 MongoDB 文檔字段。ID 字段被定義為 primitive.ObjectID,它是 MongoDB 生成的唯一辨別符。
  • 定義了一個全局變量 collection,用于表示将用于存儲書籍對象的 MongoDB 集合。使用 init() 函數設定 MongoDB 用戶端并建立集合對象。
  • 建立 Gin 路由器并定義了一個路由組,用于處理書籍 API 路由。每個路由使用 HTTP 方法和路由路徑定義,并指定相應的路由處理函數。
  • 每個路由處理函數都接收一個名為 c 的 *gin.Context 參數,以通路請求和響應對象。使用 c.JSON() 函數将 JSON 響應發送回用戶端,并指定 HTTP 狀态碼和響應體。
  • 在 createBook() 和 updateBook() 函數中,使用 c.BindJSON() 函數将請求體綁定到一個 Book 對象上。這個函數根據請求的 Content-Type 頭部确定請求體的格式(JSON、XML 等),然後将請求體反序列化為 Book 對象。
  • 在 getBook() 函數中,使用 c.Param("id") 從 URL 參數中檢索出書籍的 ID。使用 bson.M{"_id": id} 查詢在資料庫中查找指定 ID 的書籍。
  • 在 updateBook() 函數中,使用 $set 操作符僅更新書籍文檔的 Title 和 Author 字段。使用 bson.M{"$set": bson.M{"title": book.Title, "author": book.Author}} 更新表達式更新資料庫中的書籍。
  • 在 deleteBook() 函數中,使用 bson.M{"_id": id} 查詢删除資料庫中具有指定 ID 的書籍。
  • 在 main() 函數中,定義了一個監聽位址和端口的 HTTP 伺服器,并使用 router.Run() 函數啟動伺服器。
  • 在 createBook()、updateBook() 和 deleteBook() 函數中,使用 collection.InsertOne()、collection.UpdateOne() 和 collection.DeleteOne() 函數向 MongoDB 中的集合添加、更新和删除文檔。
  • 在 getBooks() 函數中,使用 collection.Find() 函數查詢集合中的所有文檔。然後使用 c.JSON() 函數将響應作為 JSON 發送回用戶端。
  • 在 getBook()、updateBook() 和 deleteBook() 函數中,使用 collection.FindOne() 函數查詢集合中的單個文檔,并使用 c.JSON() 函數将響應作為 JSON 發送回用戶端。

這個代碼示範了如何使用 Golang + Gin + MongoDB 實作一個簡單的 RESTful API,提供了基本的 CRUD 功能。使用路由組可以更好地組織和管理 API 路由,并使用 MongoDB 驅動程式在 Golang 中進行 MongoDB 操作。

Go 實作restful接口CRUD操作範例(go+gin+mongo)

補充說明一下這個代碼中使用的一些技術和函數:

  • Gin:Gin 是一個輕量級 Web 架構,具有快速路由和中間件支援,适合建構高性能 Web 應用程式。在這個代碼中,我們使用 Gin 建立路由和處理 HTTP 請求和響應。
  • MongoDB:MongoDB 是一個文檔型 NoSQL 資料庫,具有靈活的文檔模型和可擴充性。在這個代碼中,我們使用 MongoDB 存儲和管理書籍資訊。
  • bson.M 和 bson.D:MongoDB 使用 BSON(二進制 JSON)格式存儲資料,而 bson.M 和 bson.D 是 Golang 中用于表示 BSON 的映射和文檔的類型。在這個代碼中,我們使用 bson.M 和 bson.D 來建構 MongoDB 查詢和更新操作的條件和表達式。
  • c.JSON():Gin 的上下文對象(gin.Context)提供了一些有用的函數,例如 c.JSON(),用于向用戶端發送 JSON 響應。c.JSON() 函數接受一個 HTTP 狀态碼和一個結構體或 map,并将其序列化為 JSON 格式,然後發送到用戶端。
  • c.Param():c.Param() 函數用于從 URL 參數中提取值。在這個代碼中,我們使用 c.Param("id") 從 URL 中擷取書籍的 ID。
  • c.BindJSON():c.BindJSON() 函數用于将請求體綁定到一個結構體上。在這個代碼中,我們使用 c.BindJSON() 函數将請求體反序列化為 Book 對象。
  • collection.InsertOne()、collection.UpdateOne() 和 collection.DeleteOne():這些函數是 MongoDB Go 驅動程式中用于向集合中添加、更新和删除文檔的函數。
  • collection.Find() 和 collection.FindOne():這些函數是 MongoDB Go 驅動程式中用于從集合中檢索文檔的函數。collection.Find() 函數傳回一個遊标,可以疊代文檔結果集。而 collection.FindOne() 函數傳回一個單個文檔結果。
Go 實作restful接口CRUD操作範例(go+gin+mongo)

bson.M 和bson.D作用解釋

bson.M 和 bson.D 是 Golang 中用于表示 MongoDB BSON(Binary JSON)格式的映射和文檔的類型。

  • bson.M:它是一個 map 類型,其中鍵是字元串,值可以是任意類型。在 MongoDB 中,bson.M 通常用于表示查詢或更新條件。它支援嵌套結構,可以使用點号(".")來表示嵌套字段。例如,{"name.first": "Alice"} 表示一個嵌套在 name 字段下的 first 字段。
  • bson.D:它是一個有序的文檔類型,其中每個元素都是一個鍵值對。在 MongoDB 中,bson.D 通常用于表示排序條件、投影條件、更新操作和聚合管道階段。與 bson.M 不同,bson.D 是有序的,是以可以在其中指定字段的順序。例如,bson.D{{"name", 1}, {"age", -1}} 表示按照 name 升序和 age 降序的順序排序。

總的來說,bson.M 和 bson.D 都是用于在 Golang 和 MongoDB 之間進行資料交換的常用類型,它們簡化了 MongoDB 的查詢、更新、排序、投影等操作的實作過程,并提供了友善的 API 來操作 MongoDB 的 BSON 格式資料。

bson使用示例

這裡給出幾個 bson 使用示例,來更好地說明它的使用方法和作用。

建立一個 bson.M 對象:

doc := bson.M{
    "name": "Alice",
    "age":  25,
    "addr": bson.M{
        "city":    "Beijing",
        "country": "China",
    },
}

           

這裡建立了一個 bson.M 對象,其中包含了 name、age 和 addr 三個字段。其中,addr 是一個嵌套的 bson.M 對象,它包含了 city 和 country 兩個字段。這個 bson.M 對象可以用于 MongoDB 的查詢或更新操作,例如:

// 查詢 age 大于 20 歲的文檔
collection.Find(bson.M{"age": bson.M{"$gt": 20}})

// 更新 name 為 Bob 的文檔的 age 字段為 30
collection.UpdateOne(bson.M{"name": "Bob"}, bson.M{"$set": bson.M{"age": 30}})

           

建立一個 bson.D 對象:

doc := bson.D{
    {"name", "Bob"},
    {"age",  30},
    {"addr", bson.D{
        {"city",    "Beijing"},
        {"country", "China"},
    }},
}

           

這裡建立了一個 bson.D 對象,其中包含了 name、age 和 addr 三個鍵值對。與 bson.M 不同的是,bson.D 是有序的,是以可以在其中指定鍵值對的順序。這個 bson.D 對象可以用于 MongoDB 的排序、投影等操作,例如:

// 按照 age 降序排序并隻傳回 name 和 age 字段
collection.Find(bson.D{{"name", 1}, {"age", -1}}).Project(bson.D{{"name", 1}, {"age", 1}})

           

序列化和反序列化 bson:

// 将 bson.M 對象序列化為位元組數組
data, err := bson.Marshal(doc)

// 将位元組數組反序列化為 bson.M 對象
var result bson.M
err := bson.Unmarshal(data, &result)

           

這裡使用 bson.Marshal() 函數将 bson.M 對象序列化為位元組數組,然後使用 bson.Unmarshal() 函數将位元組數組反序列化為 bson.M 對象。這個方法可以用于 MongoDB Go 驅動程式中的資料交換和存儲操作。

繼續閱讀