使用 MongoDB 和 Golang 建立待办事項清單

嗨!很多人好奇一個簡單的任務表或提供這樣功能的应用程序是如何工作的。在本文中,我邀請你考慮如何用Go語言寫你的小型服務,並在不到兩小時內將一切都放入數據庫中。

我們從Golang和MongoDB開始吧。

為什麼選擇Golang?

 

我想要展示這些關鍵點:

  • 最小化設計和快速編譯
  • 带有Goroutines和通道的強有力的并发模型
  • 巨大的生態系統
  • 跨平台從盒子裡出來

另一個因素是不想花太多時間學習庫或開源解決方案。在我的情況下,我想要創建一個几乎可以即開即用的微服務。Go程式語言已經有的一切為了這點。

然而,我將指出的问题是,這門語言已經有很多非常酷的項目,這些項目為開發者解決了很多問題。例如:

  1. Gin: 高性能HTTP網絡框架
  2. Viper: 對於Go應用程序的配置解決方案(JSON,屬性,YML文件)
  3. GORM: ORM庫
  4. Protocol Buffers (Protobuf): 串列化結構化數據的最佳方法

我們不會在文章的框架內回顧它們,但或許我稍後會寫一些關於它們的內容。已經用Protobuf寫了一篇有趣的文章 “From JSON to FlatBuffers: Enhancing Performance in Data Serialization.”

安裝

安裝 Go 語言

访问 golang.org 並下載。然後,到終端機檢查它。

Shell

 

go version

IDE

只需安裝 VS Code(它是免费的)。

然後添加 Golang 擴展:

打下你的第一段代码:

Go

 

package main

import "fmt"

func main() {
   fmt.Println("Hello, World!")
}

並運行它:

Shell

 

go run main.go

就是这样!下一步是選擇收集我們數據的最佳選項。

我們的任務結構

我认为我們的第一個結構應該非常簡單。從3個字段開始:

  1. 標題(文字)
  2. 描述(文字)
  3. 狀態(布爾值)

JSON 文件作為參考:

JSON

 

{     
  "title": "Go to the groceries",     
  "description": "Purchase milk, eggs, and bread",     
  "completed": false 
}

为什么選擇 MongoDB?

我們需要為我們的任務收集數據並保持靈活性。我們不需要為某物建立模式或關係。

  1. 靈活模式
  2. 可擴展性:它支持水平擴展。
  3. 丰富的查詢語言

對於我們的小服務,我們可以以 docker-compose 方式運行。

YAML

 

# 使用 root/example 作為用戶/密碼凭证
version: '3.1'

services:

 mongo:
   image: mongo
   ports:
     - "27017:27017"
   environment:
     MONGO_INITDB_ROOT_USERNAME: root
     MONGO_INITDB_ROOT_PASSWORD: example

我比較喜歡使用 Compass GUI 來處理我們的數據(收藏、數據庫等)。在此下載

只需運行它,並將您的凭证設定在”進階選項“。它運作非常完美,當您需要時,它可以帮助您尋找問題並優化請求。

系統設計(非常小巧)

對於我們的服務,當然最好的選擇是創建 CRUD(創建、讀取、更新、刪除)方法,像這樣(沒有刪除):

Go

 

http.HandleFunc("/api/v1/add", todoHandler.AddTask)
http.HandleFunc("/api/v1/get-all", todoHandler.GetAllTasks)
http.HandleFunc("/api/v1/update", todoHandler.UpdateTask)
http.HandleFunc("/api/v1/complete", todoHandler.CompleteTask)

我想要使用按 folders 來分隔所有責任的方法。

  • 處理器 – HTTP 層
  • 模型 – 數據結構
  • 用例 – 包含服務和倉庫的業務層

項目結構可能像這樣:

Plain Text

 

todo-list/
│
├── cmd/
│   └── main.go
├── pkg/
│   └── handler
│      └── add_task.go
│      └── http_handler.go
│      └── complite_task.go
│      └── get_all_task.go
│      └── update_task.go
│   └── mapper
│       └── task.go
│   └── model
│        └── task.go
│   └── usecase
│        └── task
│           └── repository
│               └── add_task.go
│               └── complite_task.go
│               └── get_all_task.go
│               └── mongo_repositiry.go
│               └── repository.go
│               └── update_task.go
│           └── service
│               └── add_task.go
│               └── complite_task.go
│               └── get_all_task.go
│               └── service.go
│               └── update_task.go
└── go.mod

如我們所見,我們有一個 “go.mod” 文件,但它是什么呢?它是一個打包管理器或依賴管理器。我們可以安裝和新增外部庫並使用它們。對於我們的示例,我們需要使用 “go mod” 命令來初始化我們的應用程序。

  1. 初始化我們的應用程序 -> go mod init todo-service。我們將初始化所有內容;依賴管理器將創建文件並添加我們所需要的所有內容。
  2. 使用 go mod add "link"添加其他依賴。

您可以在Go Modules 參考頁面閱讀更多相關資訊。

然後,讓我們聚焦於一個方法 — 添加任務。為了進行更深入的探索和完整的代碼示例,請訪問 GitHub 倉庫 Golang 工作坊

與 MongoDB 的連接

只使用兩個依賴,我們就可以創建一個連接:

Go

 

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"

當然,我們需要將其添加到我們的服務中。請使用以下命令:

go get "go.mongodb.org/mongo-driver/mongo"

以及

go get "go.mongodb.org/mongo-driver/mongo/options"

然後,寫一段代碼:

Go

 

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 設定 MongoDB 客戶端選項
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(options.Credential{
		Username: "root",
		Password: "example",
	})

	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		log.Fatal(err)
	}

	err = client.Ping(ctx, nil)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Connected to MongoDB!")
}

我們應用程序的數據結構:

Go

 

package model

import "go.mongodb.org/mongo-driver/bson/primitive"

type Task struct {
    ID         string `json:"id"`
    Title      string `json:"title"`
    Desciption string `json:"description"`
    Completed  bool   `json:"completed"`
}

type MongoTask struct {
    ID         primitive.ObjectID `json:"id" bson:"_id"`
    Title      string             `json:"title"`
    Desciption string             `json:"description"`
    Completed  bool               `json:"completed"`
}

  • <強>任務 – 對於 HTTP 請求,MongoTask – 對於 MongoDB 層: 使用兩種結構很容易,因為有時候我們不需要將額外數據傳送給我們的用戶。例如,我們可能有一個秘密字段,如用戶名,我們必須隱藏。

1. 倉庫層次:

Go

 

type Repository interface {
    AddTask(ctx context.Context, task model.MongoTask) error
}

func (r *MongoRepository) AddTask(ctx context.Context, task model.MongoTask) error {
	task.ID = primitive.NewObjectID()


	_, err := r.collection.InsertOne(ctx, task)
}

2. 服務層次:

Go

 

type TodoService interface {
	AddTask(ctx context.Context, task model.Task) error
}

func (s *Service) AddTask(ctx context.Context, task model.Task) error {
	return s.Repo.AddTask(ctx, mapper.MapToDto(task))
}

3. 處理器層次 (用於處理 HTTP 請求):

Go

 

func (h *Handler) AddTask(w http.ResponseWriter, r *http.Request) {
	ctx := context.Background()

	var task model.Task
	err := json.NewDecoder(r.Body).Decode(&task)
	if err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	err = h.Service.AddTask(ctx, task)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusCreated)
}

現在,我們需要在 main.go 文件中安裝數據庫連接並初始化 “層次” 依賴。

Go

 

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// 設定 MongoDB 客戶端選項
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017").SetAuth(options.Credential{
		Username: "root",
		Password: "example",
	})

	client, err := mongo.Connect(ctx, clientOptions)
	if err != nil {
		log.Fatal(err)
	}

	err = client.Ping(ctx, nil)
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Connected to MongoDB!")

	// 初始化倉庫、服務和處理器
	todoRepo := repository.NewMongoRepository(client)
	todoService := service.NewService(todoRepo)
	todoHandler := handler.NewHandler(todoService)

	// 設定路由
	http.HandleFunc("/api/v1/add", todoHandler.AddTask)

	// 創建服務器
	srv := &http.Server{
		Addr:    ":8080",
		Handler: nil,
	}
  // todo: 運行服務和關閉
}

然後用請求進行測試:

HTTP

 

# curl -X POST http://localhost:8080/add
#-H "Content-Type: application/json"
#-d '{
#    "id": 1,
#    "title": "買煙草",
#    "completed": false
#}'
POST http://localhost:8080/api/v1/add
Content-Type: application/json

{
 "title": "Add description to the structure",
 "description": "your desc here..."
}

那就是全部。然後,我們必須增加並實現新方法,我們的服務準備好開始工作。

結論

我們使用 Golang 和 MongoDB 創建了一個小巧、堅固的任務管理服務。

正如我們所見,如果我們需要建立一個小型服務,我們可以非常快速的完成,而無需克服很多困難。在 我的情況下,我真的很想使用 MongoDB 作為主要數據庫,如果我有 文档。它很容易管理。

它也可以在其他国家程式語言中看到,有些地方甚至更快。例如,如果你使用 Python 和 FastAPI – 而我可能會與你持不同意見。Go 語言仍然基於 C++ 和 Java 這種程式語言的 PARADIGM,其中有 OOP。這種程式碼和Methodology 讓你保持程式碼尽可能清晰和整洁。

首先, consolidate 這樣的因素會對你理解 TDD 和其他方法論有幫助。我也要提一下,为了避免文章過度充滿指標和文字,我省略了和其他語言的性能比較。我會提一下,Go 語言在這方面沒有問題,且寫了主要函數後,你已經在你的線程中運行它了。你可以在網路上輕鬆找到比較,包括 benchmark。

要进一步學習和完整的程式碼示例,請訪問 GitHub 倉庫(之前已經提供链接)。

感謝你,小心!

Source:
https://dzone.com/articles/build-a-to-do-list-with-mongodb-and-golang