Создание списка дел с использованием MongoDB и Go

Привет, други! Многие спросили, как работают простые задачи листов или приложения, которые обеспечивают такую functionality. В этой статье я приглашаю вас рассмотреть, как вы можете написать свой небольшой сервис на Go за несколько часов и положить все в базу данных.

Пусть начнем нашу поездку с Go и MongoDB.

为什么 Go?

 

Я хочу показать ключи:

  • Минималистический дизайн и быстрое сборка
  • Сильная конкурентная модель с помощью Goroutines и каналов
  • Огромная экосистема
  • 跨平台 сразу

Другим фактором является то, что нужно немного времени для изучения библиотек или opensource решения. В моем случае я хочу создать микросервис, который будет работать практически из коробки. Язык программирования Go имеет все для этого.

然而, я хочу отметить, что язык уже богат в очень крутых проектах, которые решают множество проблем для разработчика. Такие проекты, как:

  1. Gin: High-performance HTTP web framework
  2. Viper: Configuration solution (JSON, properties, YML files) for Go applications
  3. GORM: ORM library
  4. Protocol Buffers (Protobuf): The best way to serialize structured data.

Мы их не будем рассматривать в рамках статьи, но, возможно, я позже напишу что-то о них. С Protobuf у меня уже было написано интересное сообщение “From JSON to FlatBuffers: Enhancing Performance in Data Serialization.”

Установка

Установка языка Go

Посетите golang.org и скачайте. Затем перейдите в терминал и проверьте его.

Shell

 

go version

IDE

Просто установите VS Code (он бесплатный).

А затем добавьте расширение Go:

Введите свой первый код:

Go

 

package main

import "fmt"

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

И запустите его:

Shell

 

go run main.go

Это все! Следующий шаг – выбрать лучшую опцию для сбора наших данных.

Структура нашей задачи

Я думаю, что наша первая структура должна быть очень проста. Начнем с трех полей:

  1. Заголовок (текст)
  2. Описание (текст)
  3. Статус (логическое значение)

JSON-файл как справка:

JSON

 

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

为什么MongoDB?

 Мы должны собирать данные для наших задач и быть гибкими. Нам не нужно создавать схему или связи между какими-либо вещами.

  1. Гибкая Схема
  2. Скалярность: она поддерживает горизонтальное масштабирование.
  3. ric Query Language

Для нашего небольшого сервиса мы можем запустить его как 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 для работы с нашими данными (коллекциями, базами данных и т. д.). Скачайте его здесь.

Просто запустите его и установите свои учетные данные в “Дополнительные опции“. Он работает отлично и может помочь вам найти проблемы и оптимизировать запросы, если вам это нужно.

СистемноеDesign (очень маленькое)

Конечно, для нашего сервиса лучшим вариантом будет создание методов CRUD (Create, Read, Update, Delete), чем-то вроде этого (без 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)

Я хочу использовать способ разделения всех обязанностей по папкам.

  • Handler – HTTP层次
  • Model – Структуры для данных
  • Use cases – Бизнес-слои с сервисами и репозиториями

Структура проекта может быть следующей:

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

Как我们可以 see, у нас есть файл “go.mod”, но что это за файл? Это manager packer или manager зависимостей. Мы можем устанавливать и добавлять внешние библиотеки и использовать их, как нам нужно. Для нашего примера, нам нужны пара команд с использованием “go mod”.

  1. Init нашего app -> go mod init todo-service . Мы инициализируем все; manager зависимостей создаст файлы и добавит все, что нам нужно.
  2. Добавить дополнительную зависимость с использованием go mod add "link"

Вы можете больше узнать на странице Go Modules Reference .

Тогда давайте сосредоточимся только на одном методе — добавления задач. Чтобы получить больше информации и полные примеры кода, посетите репозиторий GitHub Golang Workshop .

Соединение с MongoDB

Utilizing только двух зависимостей, мы можем создать соединение:

Go

 

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

Конечно, нам нужно добавить его в нашу службу. Utilize команды:

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

	// 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!")
}

Data структуры для нашего 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"`
}

  • Задача – для 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..."
}

}’ That’s all. Затем, мы должны добавить и реализовать новые методы, и наш сервис будет готов работать.

Заключение

Мы создали небольшой, yet robust сервис управления задачами с использованием Golang и MongoDB.

Как我们可以 see, если мы нужны для создания небольшого сервиса, мы делаем это очень быстро без множества препятствий. В моем случае, я действительно хотел бы использовать MongoDB в качестве основной базы данных, если у меня есть документы. Это просто управляется.

Также можно отметить, что было бы не хуже и в других программных языках. В некоторых местах, это даже быстрее. Например, если вы используете Python и FastAPI – и здесь я могу быть в разном мнении с вами. Язык Go до сих пор основан на парадигмах программирования, таких как C ++ и Java, где есть OOP. Такие code и методология позволяют maintain code как можно более ясным и чистым.

начинать с понимания таких факторов, как базовая часть, которая поможет вам понять TDD и другие методологии. также отмечу, что для устранения перегрузки статьи данными и текстом я пропустил сравнение скорости с другими языками. заметить, что у Go нет проблем с этим, и having written главную функцию, вы уже запустите ее в вашем потоке. Вы легко можете найти сравнения в интернете, включая벤чмаркс.

Для дальнейшего изучения и полных примеров кода посетите репозиторий GitHub (указанный ранее).

Спасибо и осторожно!

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