MongoDBとGolangで待办リストを構築する

こんにちは!多くの人が簡単なタスクシートやそのような機能を提供するアプリケーションの仕組みに好奇になっています。この記事で、私はあなたが数時間で小型サービスのGoコードを書いて、全てをデータベースに入れる方法を考えていただけることを約束します。

ここで、GolangとMongoDBを使って冒険を始めましょう。

なぜGolangを選んだのでしょうか?

 

私は主要な利点を紹介したいと思います。

  • 最小限の設計と速いコンパイル
  • Goroutinesとチャンネルを持つ強力な並行モデル
  • 大きな生態系
  • パッケージからはじめたら跨平台

もう一つの要因は、ライブラリやオープンソースの解決策に多くの時間を費やす必要がないことです。私の場合、ほとんどの場で外から始動するマイクロサービスを作りたいと考えています。Golangプログラミング言語はこれに完璧に適しています。

しかし、言語にはすでに非常に素晴らしいプロジェクトが多く、開発者の多くの問題を解決しています。このようなプロジェクトを例に挙げます。

  1. Gin: 高性能のHTTPウェブフレームワーク
  2. Viper: Goアプリケーション用の設定解決策(JSON、プロperties、YMLファイル)
  3. GORM: ORMライブラリ
  4. Protocol Buffers (Protobuf): 構造化されたデータを序列化する最善の方法

この記事の枠内ではレビューしないが、もしかしたら後で何か書くかもしれない。Protobufについては、すでに興味深い記事「FFrom JSON to FlatBuffers:

インストール

Go言語のインストール

golang.orgにアクセスし、ダウンロードします。

Shell

 

go version

IDE

Just install VS Code (it’s free).

And add the Golang extension:

Type your first code:

Go

 

package main

import "fmt"

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

And run it:

Shell

 

go run main.go

That’s it!

タスクの構造

最初の構造はとてもシンプルであるべきだと思います。

  1. Title (text)
  2. Description (text)
  3. Status (bool)

参考としてJSONファイル:

JSON

 

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

なぜMongoDBなのか?

私たちはタスクに适したデータを集め、柔軟性が必要です。物と物の間にスキーマや関連性を作成する必要はありません。

  1. 柔軟なスキーマ
  2. スケーラビリティ: 水平スケーリングをサポートします。
  3. 豊富なクエリ言语

私たちの小さなサービスでは、docker-composeで実行できます。

YAML

 

# ルート/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)

私はすべての責任をフォルダーに分離する方法を使用したいです。

  • ハンドラー – 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 Reference ページを読むことができます。

次に、一度だけメソッドを焦点に置きましょうータスクの追加。完全なコードの例を見るには、GitHub リポジトリ Golang Workshop に行ってください。

MongoDBへの接続

2つの依存関係だけを使用して接続を作成できます。

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

  • Task – HTTP要求に対するMongoTaskはMongoDB層に対応しています: この2つの構造を使用するのは簡単です、なぜなら私たちが追加のデータをユーザーに送信する必要がない場合があるからです。たとえば、秘密のフィールドがある場合があり、これは「ユーザー名」のように隠す必要があります。

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,
	}
  // サービスを実行して終了
}

そして、以下の要求でテストします。

HTTP

 

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

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

}’That’s all. Then, we must add and implement new methods, and our service will be ready to work.

結論

GolangとMongoDBを使用して小さくても強力なタスク管理サービスを作成しました。

私たちが小さなサービスを作成する必要がある場合、多くの障碍なく素早く作成できることがわかります。私の場合、ドキュメントを持つ場合はMongoDBを主なデータベースとして使用したいと思います。管理が簡単です。

他のプログラミング言語に比べても劣くはないし、いくつかの場ではより速いこともある。たとえば、PythonとFastAPIを使用しているときにも、ここであなたと同意することがあり得ます。Go言語は、C++やJavaのようなプログラミング言語のパラダイムに基づいていますので、OOPがあります。このようなコードと方法論は、可能な限りコードを明確かつクリーンに保ちます。

始めに、基本的な要素を掌握することが重要であり、TDDや他の方法論を理解するのを助けることができます。また、記事に指标やテキストを充てていないようにして、他の言語との性能比較を省くことに注意しています。Golangはこの点で問題がないこと、主要な関数を書いた後、すでにスレッド内で実行できること、インターネット上に、ベンチマークを含む比較が簡単に見つけられることを指摘します。

さらなる探索や完全なコード例を見るには、以前にリンクされたGitHubレポジトリに行ってください。

ありがとうございます。お互いに注意を払いましょう!

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