Erstellen einer To-Do-Liste mit MongoDB und Golang

Hallo! Viele haben sich gefragt, wie eine einfache Aufgabenliste oder Anwendungen, die solche Funktionalität bieten, funktionieren. In diesem Artikel lade ich Sie ein, zu erkunden, wie Sie Ihren kleinen Dienst in Go in wenigen Stunden schreiben und alles in einer Datenbank platzieren können.

Lassen Sie uns unsere Reise mit Golang und MongoDB beginnen.

Warum Golang?

 

Ich möchte die Schlüssel zeigen:

  • Minimalistisches Design und schnelle Kompilierung
  • Starke Konkurrenzmodelle mit Goroutines und Kanälen
  • Im großenÖkosystem
  • Cross-Plattform von der Box an

Ein anderer Faktor besteht darin, dass nicht viel Zeit für die Lektüre von Bibliotheken oder Open-Source-Lösungen verwendet werden sollte. In meinem Fall möchte ich einen Mikrodienst erstellen, der fast aus der Box funktioniert. Die Programmiersprache Golang hat alles dafür.

Ich möchte jedoch darauf hinweisen, dass die Sprache bereits reich an sehr coolen Projekten ist, die vielen Problemen für den Entwickler Lösungen bieten. Projekte wie:

  1. Gin: High-performance HTTP-Webframework
  2. Viper: Konfigurationslösung (JSON, Eigenschaften, YML-Dateien) für Go-Anwendungen
  3. GORM: ORM-Bibliothek
  4. Protokolbuffers (Protobuf): Der beste Weg, um strukturierte Daten zu serialisieren.

Wir werden sie nicht innerhalb des Artikel- Rahmens überprüfen, aber vielleicht werde ich später etwas dazu schreiben. Mit Protobuf habe ich bereits einen interessanten Artikel geschrieben: „From JSON to FlatBuffers: Enhancing Performance in Data Serialization.“

Installation

Installation von Go-Sprache

Besuchen Sie golang.org und laden Sie die Dateien herunter. Navigieren Sie dann zum Terminal und überprüfen Sie diese.

Shell

 

go version

IDE

Installieren Sie einfach VS Code (es ist kostenlos).

Und fügen Sie anschließend die Golang-Erweiterung hinzu:

Geben Sie Ihren ersten Code ein:

Go

 

package main

import "fmt"

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

Und führen Sie ihn aus:

Shell

 

go run main.go

Das ist es! Der nächste Schritt besteht darin, die beste Option auszuwählen, um unsere Daten zu sammeln.

Unsere Aufgabenstruktur

Ich denke, unser erster Struktur sollte wirklich einfach sein. Beginnen wir mit 3 Feldern:

  1. Titel (Text)
  2. Beschreibung (Text) 
  3. Status (bool)

 JSON-Datei als Beispiel:

JSON

 

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

Warum MongoDB?

Wir müssen Daten für unsere Aufgaben sammeln und flexibel arbeiten. Wir müssen kein Schema oder eine Beziehung zwischen etwas erzeugen.

  1. Flexibles Schema
  2. Skalierbarkeit: Es unterstützt horizontale Skalierung.
  3. Reiches Abfragesprache

Für unser kleines Service können wir es als docker-compose ausführen.

YAML

 

 # Verwende root/example als Benutzer/Passwort-Zugangsdaten 
version: '3.1'

services:

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

Ich bevorzuge die Compass GUI für die Arbeit mit unseren Daten (Sammlungen, Datenbanken etc.). Lade es hier herunter.

Führe es einfach aus und setze deine Zugangsdaten in „Erweiterte Optionen„. Es funktioniert perfekt und kann dir hilfreich sein, Probleme zu finden und Anfragen zu optimieren, wenn du das brauchst.

Systementwicklung (Really Small)

Für unser Service ist es natürlich die beste Option, CRUD-Methoden (Create, Read, Update, Delete) zu erstellen, etwas wie das folgende (ohne Delete):

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)

Ich möchte die Art verwenden, alle Verantwortlichkeiten durch Ordner zu trennen.

  • Handler – HTTP-Schicht
  • Model – Strukturen für Daten
  • Use cases – Geschäftslogik mit Service und Repository

Der Projektstruktur könnte so aussehen:

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

Wie wir sehen können, haben wir eine Datei „go.mod“, aber was ist das? Es ist ein Paketmanager oder Abhängigkeitsmanager. Wir können externe Bibliotheken installieren und hinzufügen und sie ebenfalls verwenden. Für unser Beispiel müssen wir einige Befehle verwenden, die mit „go mod“ arbeiten.

  1. Initiale unsere App -> go mod init todo-service . Wir werden alles initialisieren; der Abhängigkeitsmanager wird Dateien erzeugen und alles, was wir benötigen, hinzufügen.
  2. Füge eine zusätzliche Abhängigkeit hinzu, indem du go mod add "link" verwendest.

Du kannst mehr Informationen auf der Go Modules Reference -Seite lesen.

Nun konzentriere dich nur auf eine einzige Methode – das Hinzufügen von Aufgaben. Um weitere Erkundungen und vollständige Codebeispiele zu finden, besuche das GitHub-Repository Golang Workshop.

Verbindung mit MongoDB

Mit nur zwei Abhängigkeiten können wir eine Verbindung herstellen:

Go

 

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

Natürlich müssen wir sie zu unserem Service hinzufügen. Bitte verwende die Befehle:

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

und

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

Dann schreibe einen Codeabschnitt:

Go

 

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

	// Set MongoDB Client Options
	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!")
}

Datenstrukturen für unsere App:

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

  • Aufgabe – für HTTP-Anfrage, MongoTask – für MongoDB-Schicht: Die Verwendung von zwei Strukturen ist einfach, weil manchmal keine zusätzlichen Daten an die Benutzer senden muss. Zum Beispiel könnten wir ein geheimes Feld haben, wie einen Benutzernamen, der versteckt werden muss.

1. Repository-Schicht:

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. Diensteschicht:

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. Handler-Schicht (zur Verarbeitung von HTTP-Anfragen):

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

Jetzt müssen wir die Datenbankverbindung installieren und die Abhängigkeit „layers“ im Datei main.go initialisieren.

Go

 

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

	// Setze MongoDB-Client-Optionen
	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!")

	// Initialisiere Repository, Dienst und Handler
	todoRepo := repository.NewMongoRepository(client)
	todoService := service.NewService(todoRepo)
	todoHandler := handler.NewHandler(todoService)

	// Richte Routen ein
	http.HandleFunc("/api/v1/add", todoHandler.AddTask)

	// Erstelle einen Server
	srv := &http.Server{
		Addr:    ":8080",
		Handler: nil,
	}
  // todo: Starte Dienst und Beenden
}

Und testen Sie es mit der Anfrage:

HTTP

 

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

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

Das ist alles. Dann müssen wir neue Methoden hinzufügen und implementieren, und unser Dienst ist bereit zu arbeiten.

Fazit

Wir haben mit Golang und MongoDB ein kleines, aber solides Aufgabenverwaltungsservice geschaffen.

Wie wir sehen können, wenn wir ein kleines Service bauen müssen, machen wir das sehr schnell ohne viele Hindernisse. In meinem Fall würde ich MongoDB als Hauptdatenbank für Dokumente wirklich gerne verwenden, weil es einfach zu verwalten ist.

Es kann auch festgestellt werden, dass es in anderen Programmiersprachen nicht schlechter wäre. In einigen Fällen ist es sogar schneller. Zum Beispiel, wenn Sie Python und FastAPI verwenden – und in diesem Punkt könnte ich mich von Ihnen unterscheiden. Die Sprache Golang basiert immer noch auf den Paradigmen von Programmiersprachen wie C++ und Java, die OOP haben. Solcher Code und Methodik ermöglichen es Ihnen, den Code so klar und sauber wie möglich zu halten.

Zum Anfang ist es gut, solche Faktoren wie eine Basis zu konsolidieren, die Ihnen helfen wird, TDD und andere Methoden zu verstehen. Ich will auch darauf hinweisen, dass ich aus Gründen der Übersichtlichkeit und um die Überschrift des Artikels nicht mit Zahlen und Text überfrachten zu vermeiden, die Vergleiche mit anderen Sprachen weglassen habe. Ich möchte darauf hinweisen, dass Golang mit diesen Problemen kein Problem hat und nachdem Sie die Hauptfunktion geschrieben haben, führen Sie sie einfach in Ihrem Thread aus. Sie finden leicht im Internet Vergleiche, einschließlich Benchmarks.

Für weitere Erkundung und vollständige Codebeispiele besuchen Sie das GitHub-Repository (das zuvor verlinkt wurde).

Vielen Dank und viel Erfolg!

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