MongoDB와 Golang으로 할 일 목록 만들기

안녕하세요! 간단한 업무 시트 또는 이러한 기능을 제공하는 응용 프로그램의 작동 방법이 어떻게 되는지 많은 사람들이 의심하고 있습니다. 이 記事에서는 어떻게 Go로 작은 서비스를 짧은 시간 내에 書く 수 있고, 모든 것을 데이터베이스로 옮길 수 있는지 여러분을 초대하고자 합니다.

Golang과 MongoDB로 우리의 여행을 시작해 보겠습니다.

Golang을 왜 사용하는가?

 

KEY를 보여드릴 것입니다:

  • 最小化 디자인과 빠른 컴파일
  • Goroutines와 채널을 사용한 강한 并行 모델
  • 대량의 生態系
  • Cross-platform 로부터

또 다른 요소는 라이브러리 또는 오픈 소스 솔루션에 대한 공부를 많이 하지 않는 것입니다. 제 사례에서는 近乎 即开即用的 마이크로 서비스를 만들고자 합니다. Golang 프로그래밍 언어는 이에 충분한 것을 제공합니다.

그러나 언어는 이미 developers를 도울 수 있는 非常に 멋진 프로젝트를 가득 갖추고 있습니다. 이러한 프로젝트들은:

  1. Gin: 高性能 HTTP 웹 프레임워크
  2. Viper: Go 应用程序的 配置解决方案 (JSON, 属性, YML 文件)
  3. GORM: ORM 라이브러리
  4. Protocol Buffers (Protobuf): 구조ured data를 序列化的 最佳方式

이 글의 틀 안에서 검토하지는 않겠지만 나중에 이에 대해 글을 쓰게 될지도 모르겠습니다. 프로토버프와 관련해서는 이미 “F에서 JSON으로 플랫버퍼로“라는 흥미로운 글을 쓴 적이 있습니다: 데이터 직렬화 성능 향상

설치

Go 언어 설치

golang.org에 방문하여 다운로드하세요. 그런 다음 터미널로 이동하여 확인합니다.

Shell

 

go version

IDE

설치하기만 하면 됩니다(무료입니다).

그리고 Golang 확장자를 추가합니다.

첫 코드를 입력합니다.

Go

 

package main

import "fmt"

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

그리고 실행합니다.

Shell

 

go run main.go

그게 다입니다! 다음 단계는 데이터를 수집하는 데 가장 적합한 옵션을 선택하는 것입니다.

작업 구조

첫 번째 구조는 정말 간단해야 한다고 생각합니다. 3개의 필드로 시작하겠습니다.

  1. 제목(텍스트)
  2. 설명(텍스트)
  3. 상태(bool)

참조용 JSON 파일:

JSON

 

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

왜 몽고DB일까요?

우리는 업무에 필요한 데이터를 수집하고 유연해야 합니다. 스키마나 관계를 만들 필요가 없습니다.

  1. 유연한 스키마
  2. 확장성: 수평적 확장을 지원합니다.
  3. 풍부한 쿼리 언어

작은 서비스의 경우 docker-compose로 실행할 수 있습니다.

YAML

 

# 사용자/암호 자격 증명으로 루트/예제 사용
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” 파일을 보았지만 이것이 무엇인지 알아보겠습니다. 이것은 Paket Manager 또는 依存성 관리자입니다. 외부 라이브러리를 설치하고 추가하고 사용할 수 있습니다. 우리의 예제를 위해서는 “go mod”을 사용하여 좀 더 많은 명령어가 필요합니다.

  1. 我们的应用程序初始化 -> go mod init todo-service。 我们将初始化所有内容; 依存성 관리자가 파일을 생성하고 我们需要的一切를 추가합니다.
  2. 使用go mod add "link" 添加额外的依赖项。

您可以在 Go Modules Reference 页面 上阅读更多信息。

그리고, 오직 하나의 方法을 重点를 줍니다 – 태스크 추가입니다. 더 深入的探索과 compete code 예시를 보려면, GitHub repository Golang Workshop를 방문하십시오.

MongoDB 연결

두 가지 依存성 only로 연결을 Create할 수 있습니다.

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 – 몽고DB 계층의 경우: 두 가지 구조를 사용하는 것은 사용자에게 추가 데이터를 보낼 필요가 없는 경우가 있기 때문에 쉽습니다. 예를 들어, 사용자 이름과 같이 숨겨야 하는 비밀 필드가 있을 수 있습니다.

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

	// 몽고DB 클라이언트 옵션 설정
	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": "식료품 구매",
# "completed": false
#}'
POST http://localhost:8080/api/v1/add
Content-Type: application/json

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

그게 전부입니다. 이제 새로운 메서드를 추가하고 구현하면 서비스가 작동할 준비가 된 것입니다.

결론

Golang과 MongoDB를 사용하여 작지만 강력한 작업 관리 서비스를 만들었습니다.

보시다시피 작은 서비스를 구축해야 한다면 많은 장애물 없이 정말 빠르게 해낼 수 있습니다. 제 경우에는 문서가 있는 경우 MongoDB를 메인 데이터베이스로 사용하고 싶습니다. 관리하기 쉽기 때문이죠.

OOP 기반의 언어들과 마찬가지로 Golang 언어도 다른 프로그래밍 언어들과 별 나쁜 것이 없습니다. 어느 정도 더 빠르게 동작할 수 있습니다. 예를 들어 Python과 FastAPI를 사용하는 것과 관련해서, 여기에서 여러분과 의견이 다를 수 있습니다.

시작할 때에는 기반으로 보고자 하는 것과 이를 이해하기 위한 TDD 및 기타 메소드들을 이해하는 것을 중요視할 것입니다. 記事에 성능과 텍스트를 과목에 적용하는 것을 避け기 위해 다른 언어들과의 比较を 省略했습니다. 需要注意하는 것은, Golang은 이러한 것에 문제를 겪지 않고, 주요 함수를 쓰면 스레드에서 이를 실행할 수 있습니다. 인터넷에서 包括 ベンチマーク이나 比較 정보를 쉽게 찾을 수 있습니다.

더 deeply 探究하고 完全한 코드 예시를 보려면 GitHub 저장소(이전에 연결됐습니다)를 방문하십시오.

감사합니다 그리고 주의 please!

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