Bouwen van een takenlijst met MongoDB en Golang

Hallo! Velen hebben zich gefragd hoe een eenvoudige takenlijst of applicaties die dergelijke functionaliteit bieden werken. In dit artikel nodig ik u uit om te denken over hoe u uw kleine dienst in Go binnen enkele uren kunt schrijven en alles in een database kunt plaatsen.

Laten we ons avontuur beginnen met Golang en MongoDB.

Waarom Golang?

 

Ik wil de sleutels tonen:

  • Minimalistisch ontwerp en snelle compilatie
  • Sterke concurrency-model met Goroutines en kanalen
  • Groot ecosysteem
  • Cross-platform uit de box

Een ander factor is om niet veel tijd te besteden aan het bestuderen van bibliotheken of open-source oplossingen. In mijn geval wil ik een microservice creëren die bijna direct werkt. De programmeertaal Golang heeft daarvoor alles inbegrepen.

Ik zal echter opmerken dat de taal al rijk is in erg cool projecten dat veel problemen voor de ontwikkelaar oplost. Projecten zoals:

  1. Gin: High-performance HTTP web framework
  2. Viper: Configuratiesolution (JSON, properties, YML bestanden) voor Go-toepassingen
  3. GORM: ORM-bibliotheek
  4. Protocol Buffers (Protobuf): De beste manier om gestructureerde data te serialiseren.

We zullen ze niet binnen het kader van het artikel beoordelen, maar misschien zal ik later iets over ze schrijven. Met Protobuf heb ik al een interessant artikel geschreven, “From JSON to FlatBuffers: Enhancing Performance in Data Serialization.”

Installatie

Installeer de Go-taal

Bekijk golang.org en download. Dan gaat u naar de terminal en controleert u het.

Shell

 

go version

IDE

Installeer gewoon VS Code (het is gratis).

En voeg dan de Golang-extensie toe:

Typ uw eerste code:

Go

 

package main

import "fmt"

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

En voer het uit:

Shell

 

go run main.go

Dat is het! Het volgende stap is om de beste optie uit te kiezen om onze data te verzamelen.

Onze Taakstructuur

Ik denk dat onze eerste structuur erg eenvoudig moet zijn. Beginnen we met 3 velden:

  1. Titel (tekst)
  2. Beschrijving (tekst) 
  3. Status (bool)

 JSON-bestand als referentie:

JSON

 

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

Waarom MongoDB?

We moeten gegevens verzamelen voor onze taken en moeten flexibel zijn. We hoeven geen schema of relatie tussen objecten aan te maken.

  1. Flexibel Schema
  2. Scalabiliteit: Het ondersteunt horizontale schaalbaarheid.
  3. rijke Querytaal

Voor onze kleine dienst kunnen we het als docker-compose draaien.

YAML

 

# Gebruik root/example als gebruikersnaam/wachtwoordreferenties 
version: '3.1'

services:

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

Ik heb een voorkeur voor Compass GUI om te werken met onze gegevens (collecties, databases, enz.). Download het hier.

Start het en stel uw referenties in voor “Geavanceerde opties“. Het werkt perfect en kan problemen helpen opsporen en aanvragen optimaliseren als dat nodig is.

Systeemontwerp (Really Small)

Voor onze dienst is het beste om CRUD (Create, Read, Update, Delete) methoden te maken, iets als dit (zonder 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)

Ik wil de manier gebruiken om alle verantwoordelijkheden door middel van mappen te scheiden.

  • Handler – HTTP laag
  • Model – Structuren voor gegevens
  • Use cases – Geschiedenis met dienst en archief

Het projectstructuur zou er misschien zo uit kunnen zien:

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

Als we kunnen zien, hebben we een “go.mod” bestand, maar wat is het? Het is een pakkerbeheerder of afhankelijkheidbeheerder. We kunnen externe bibliotheken installeren en toevoegen en ze ook gebruiken. Voor ons voorbeeld zijn er enkele commando’s nodig die gebruik maken van “go mod”.

  1. Initialiseer onze app -> go mod init todo-service . We zullen alles initialiseren; de afhankelijkheidbeheerder zal bestanden aanmaken en alles dat we nodig hebben toevoegen.
  2. Voeg een extra afhankelijkheid toe met go mod add "link"

U kunt meer lezen op de Go Modules Reference pagina.

Vervolgens kunnen we ons specifieker richten op één methode – het toevoegen van taken. Voor meer informatie en volledige codevoorbeelden, bezoek de GitHub-repository Golang Workshop.

Verbinding met MongoDB

Met behulp van slechts twee afhankelijkheden kunnen we een verbinding maken:

Go

 

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

Natuurlijk moeten we het aan onze dienst toevoegen. Gebruik de commando’s:

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

en 

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

Vervolgens schrijven we een stuk code:

Go

 

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

	// Stel MongoDB clientopties in
	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!")
}

Data structuren voor onze 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"`
}

  • Taak – voor HTTP-verzoek, MongoTask – voor MongoDB-laag: Het gebruik van twee structuren is gemakkelijk omdat we soms geen extra data naar onze gebruikers hoeven te sturen. Bijvoorbeeld, we kunnen een geheime veld hebben, zoals een gebruikersnaam, die we moeten verbergen.

1. Repositorylaag:

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

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. Handlerlaag (om HTTP-verzoeken te verwerken):

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

Nu moeten we de databaseverbinding installeren en de “layers”-afhankelijkheid initialiseren in het main.go bestand.

Go

 

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

	// Stel MongoDB-clientopties in
	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!")

	// Initializeer repository, dienst en handler
	todoRepo := repository.NewMongoRepository(client)
	todoService := service.NewService(todoRepo)
	todoHandler := handler.NewHandler(todoService)

	// Setup routes
	http.HandleFunc("/api/v1/add", todoHandler.AddTask)

	// Maak een server aan
	srv := &http.Server{
		Addr:    ":8080",
		Handler: nil,
	}
  // todo: draai dienst en afsluiten
}

En test het met het verzoek:

HTTP

 

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

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

Dat is alles. Vervolgens moeten we nieuwe methodes toevoegen en implementeren, en zijn onze dienst klaar om te werken.

Conclusie

We hebben een klein, maar robuust takenbeheeringsservice gemaakt gebruikmakend van Golang en MongoDB.

Als we kunnen zien, als we een kleine dienst moeten bouwen, doen we dat echt snel zonder veel obstakels. In mijn geval zou ik MongoDB echt graag willen gebruiken als hoofdbestand voor documenten. Het is simpel te beheren.

Het kan ook worden opgemerkt dat het niet slechter zou zijn in andere programmeertalen. In sommige gevallen is het zelfs sneller. Bijvoorbeeld, als je Python en FastAPI gebruikt – en hier zou ik misschien met u afwijken. De taal Golang is nog steeds gebaseerd op de Paradigma’s van programmeertalen als C++ en Java, waar er OOP is. Zo’n code en methodologie laten u de code zo helder en schoon mogelijk houden.

Voor een start zal het goed zijn om zo’n factoren als een basis te versterken, die u helpen begrijpen TDD en andere methodieken. Ik zal ook noteren dat om overloading van het artikel met metrics en tekst te vermijden, ik de vergelijking met andere talen heb overgeslagen. Ik zal noteren dat Golang er geen problemen mee heeft en na het schrijven van de hoofdfunctie, schrijft u het al in uw thread. U kunt gemakkelijk vergelijkingen op het internet vinden, inclusief benchmarkingen.

Voor verdere verkenning en volledige codevoorbeelden, bezoek de GitHub-repository (die eerder werd vermeld).

Bedankt en tot ziens!

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