Constructing a To-Do Record With MongoDB and Golang – DZone – Uplaza

Hello, there! Many have questioned how a easy job sheet or functions that present such performance work. On this article, I invite you to think about how one can write your small service in Go in a few hours and put all the things in a database.

Let’s begin our journey with Golang and MongoDB.

Why Golang?

 

I need to present the keys:

  • Minimalistic design and quick compilation
  • Robust concurrency mannequin with Goroutines and channels
  • Enormous ecosystem
  • Cross-platform from the field

One other issue is to not spend a lot time finding out libraries or open-source options. In my case, I need to create a microservice that can work virtually out of the field. The Golang programming language has all the things for this.

I’ll word, nonetheless, that the language is already wealthy in very cool tasks that clear up many issues for the developer. Initiatives resembling: 

  1. Gin: Excessive-performance HTTP net framework 
  2. Viper: Configuration answer (JSON, properties, YML recordsdata) for Go functions
  3. GORM: ORM library
  4. Protocol Buffers (Protobuf): One of the simplest ways to serialize structured knowledge

We is not going to assessment them inside the article’s framework, however maybe I’ll write one thing about them later. With Protobuf, I’ve already written an attention-grabbing article, “From JSON to FlatBuffers: Enhancing Performance in Data Serialization.”

Set up

Putting in Go Language

Go to golang.org and obtain. Then, go to the terminal and examine it.

IDE

Simply set up VS Code (it is free).

After which add the Golang extension:

Add the Golang extension

Kind your first code:

bundle principal

import "fmt"

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

And run it:

That is it! The subsequent step is to decide on the best choice to gather our knowledge.

Our Activity Construction

I believe our first construction ought to be actually easy. Let’s begin with 3 fields:

  1. Title (textual content)
  2. Description (textual content) 
  3. Standing (bool)

 JSON file as a reference:

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

Why MongoDB?

 We have to accumulate knowledge for our duties and be versatile. We needn’t create a schema or relationship between one thing.

  1. Versatile Schema
  2. Scalability: It helps horizontal scaling.
  3. Wealthy Question Language

For our small service, we will run it as docker-compose.

# Use root/instance as consumer/password credentials
model: '3.1'

providers:

 mongo:
   picture: mongo
   ports:
     - "27017:27017"
   setting:
     MONGO_INITDB_ROOT_USERNAME: root
     MONGO_INITDB_ROOT_PASSWORD: instance

I want Compass GUI for working with our knowledge (collections, databases, and so on.). Obtain it right here.

Simply run it and set your credentials to “Advanced options.” It really works completely and may help you discover issues and optimize requests should you want them.

System Design (Actually Small)

For our service, in fact, the best choice is to create CRUD (Create, Learn, Replace, Delete) strategies, one thing like this (with out delete):

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)

I need to use the best way to separate all duties by folders.

  • Handler – HTTP layer
  • Mannequin – Constructions for knowledge
  • Use circumstances – Enterprise layers with service and repository

The undertaking construction may be like this:

todo-list/
│
├── cmd/
│   └── principal.go
├── pkg/
│   └── handler
│      └── add_task.go
│      └── http_handler.go
│      └── complite_task.go
│      └── get_all_task.go
│      └── update_task.go
│   └── mapper
│       └── job.go
│   └── mannequin
│        └── job.go
│   └── usecase
│        └── job
│           └── 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

As we will see, we have now a “go.mod” file, however what’s it? It’s a packer supervisor or dependency supervisor. We are able to set up and add exterior libs and use them as effectively. For our instance, we’d like a few instructions utilizing “go mod”.

  1. Init our app -> go mod init todo-service . We are going to init all the things; the dependency supervisor will create recordsdata and add all the things we’d like.
  2. Add further dependency utilizing go mod add "link"

You’ll be able to learn extra on the Go Modules Reference web page.

Then, let’s give attention to just one methodology — including duties. For additional exploration and full code examples, go to the GitHub repository Golang Workshop.

Connection to MongoDB

Utilizing solely two dependencies, we will create a connection:

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

In fact, we have to add it to our service. Please use the instructions:

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

and 

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

Then, write a chunk of code:

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

	// Set MongoDB shopper choices
	clientOptions := choices.Shopper().ApplyURI("mongodb://localhost:27017").SetAuth(choices.Credential{
		Username: "root",
		Password: "example",
	})

	shopper, err := mongo.Join(ctx, clientOptions)
	if err != nil {
		log.Deadly(err)
	}

	err = shopper.Ping(ctx, nil)
	if err != nil {
		log.Deadly(err)
	}

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

Information buildings for our app:

bundle mannequin

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

sort Activity struct {
    ID         string `json:"id"`
    Title      string `json:"title"`
    Desciption string `json:"description"`
    Accomplished  bool   `json:"completed"`
}

sort MongoTask struct {
    ID         primitive.ObjectID `json:"id" bson:"_id"`
    Title      string             `json:"title"`
    Desciption string             `json:"description"`
    Accomplished  bool               `json:"completed"`
}
  • Activity – for HTTP request, MongoTask – for MongoDB layer: Utilizing two buildings is straightforward as a result of typically we needn’t ship extra knowledge to our customers. For instance, we would have a secret subject, like a username, which we should cover.

1. Repository layer:

sort Repository interface {
    AddTask(ctx context.Context, job mannequin.MongoTask) error
}

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


	_, err := r.assortment.InsertOne(ctx, job)
}

2. Service layer:

sort TodoService interface {
	AddTask(ctx context.Context, job mannequin.Activity) error
}

func (s *Service) AddTask(ctx context.Context, job mannequin.Activity) error {
	return s.Repo.AddTask(ctx, mapper.MapToDto(job))
}

3. Handler layer (to course of HTTP requests):

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

	var job mannequin.Activity
	err := json.NewDecoder(r.Physique).Decode(&job)
	if err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

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

	w.WriteHeader(http.StatusCreated)
}

Now, we have to set up the database connection and initialize the “layers” dependency within the principal.go file.

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

	// Set MongoDB shopper choices
	clientOptions := choices.Shopper().ApplyURI("mongodb://localhost:27017").SetAuth(choices.Credential{
		Username: "root",
		Password: "example",
	})

	shopper, err := mongo.Join(ctx, clientOptions)
	if err != nil {
		log.Deadly(err)
	}

	err = shopper.Ping(ctx, nil)
	if err != nil {
		log.Deadly(err)
	}

	log.Println("Connected to MongoDB!")

	// Initialize repository, service, and handler
	todoRepo := repository.NewMongoRepository(shopper)
	todoService := service.NewService(todoRepo)
	todoHandler := handler.NewHandler(todoService)

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

	// Create a server
	srv := &http.Server{
		Addr:    ":8080",
		Handler: nil,
	}
  // todo: run service and shutdown
}

And take a look at it with the request:

# 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 material-Kind: utility/json

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

That is all. Then, we should add and implement new strategies, and our service shall be able to work.

Conclusion

We have created a small, but sturdy job administration service utilizing Golang and MongoDB.

As we will see, if we have to construct a small service, we do it actually quick with out many obstacles. In my case, I would like to make use of MongoDB as the primary database if I’ve paperwork. It is simply straightforward to handle.

It will also be famous that it will be no worse in different programming languages. In some locations, it is even quicker. For instance, should you use Python and FastAPI – and right here I could disagree with you. The Golang language continues to be primarily based on the paradigms of programming languages like C++ and Java, the place there’s OOP.  Such code and methodology let you maintain the code as clear and clear as doable.

For a begin, will probably be good to consolidate such elements as a base, which can make it easier to perceive TDD and different methodologies. I will even word that to keep away from overloading the article with metrics and textual content, I omitted evaluating efficiency with different languages. I’ll word that Golang has no issues with this, and having written the primary perform, you already run it in your thread. You’ll be able to simply discover comparisons on the Web, together with benchmarks.

For additional exploration and full code examples, go to the GitHub repository (linked earlier).

Thanks and take care!

Share This Article
Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

Exit mobile version