clean-architecture 구성

2024. 11. 24. 22:52·devops/go

go로 api를 구성하는데 최소버전으로 clean-architecture를 구성하도록 하겠다.

 

DB는 aws rds에서 최소버전으로 발급받았다.

teleport와 db를 연결한 후에

 

$ tsh proxy db ggocamping-db-v1 --port 3036 --db-user ggorockee
  • handlers: fiber에서 api를 호출하면 실제로 실행되는 부분
  • routes:  routing에 따른 handlers를 처리
  • presenter: api reposne 부분

으로 구분하여 폴더트리를 만들고 그 안에 각각에 맞게 개발을 진행하도록 한다.

DB에 저장되는 entities부터 정의하자.

 

pkg/entities/spot.go

package entities

import (
	"gorm.io/gorm"
	"time"
)

type Spot struct {
	Id        uint    `json:"id" gorm:"primaryKey"`
	Title     string    `json:"title"`
	Author    string    `json:"author"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

type DeleteRequest struct {
	Id string `json:"id"`
}

 

이렇게 파일을 만들어 DB에 저장할 수 있는 파일 형태를 만들기로 했다. 여기에 나와있는 author는 나중에 로그인 했을 때 그 때 이름으로 하겠다.

 

pkg/spot/repository.go

package spot

import (
	"camping-backend-with-go/pkg/entities"
	"gorm.io/gorm"
)

type Repository interface {
	CreateSpot(spot *entities.Spot) (*entities.Spot, error)
}

type repository struct {
	DBConn *gorm.DB
}

func NewRepo(dbconn *gorm.DB) Repository {
	return &repository{
		DBConn: dbconn,
	}
}

func (r *repository) CreateSpot(spot *entities.Spot) (*entities.Spot, error) {
	result := r.DBConn.Create(spot)
	if result.Error != nil {
		return nil, result.Error
	}
	return spot, nil

}
  • NewRepo()에서 *gorm.DB를 초기화한다.

 

아래와 같이 서비스를 만들어주게 되면 간단하게 pkg쪽은 완료가 된다.

pkg/spot/service.go

package spot

import (
	"camping-backend-with-go/pkg/entities"
)

type Service interface {
	InsertSpot(spot *entities.Spot) (*entities.Spot, error)
}

type service struct {
	repository Repository
}

func NewService(r Repository) Service {
	return &service{
		repository: r,
	}
}

// InsertSpot is a service layer that helps insert Spot in SpotShop
func (s *service) InsertSpot(spot *entities.Spot) (*entities.Spot, error) {
	return s.repository.CreateSpot(spot)
}

 


api

 

먼저 api respone가 어떤형태로 나타날지 아래와 같이 짜고나서

presenter/spot.go

package presenter

import (
	"camping-backend-with-go/pkg/entities"
	"github.com/gofiber/fiber/v2"
)

type Spot struct {
	Id     uint `json:"id"`
	Title  string `json:"title"`
	Author string `json:"author"`
}

func SpotSuccessResponse(data *entities.Spot) *fiber.Map {
	spot := Spot{
		Id:     data.Id,
		Title:  data.Title,
		Author: data.Author,
	}
	return &fiber.Map{
		"status": true,
		"data":   spot,
		"error":  nil,
	}
}

func SpotsSuccessResponse(data *[]Spot) *fiber.Map {
	return &fiber.Map{
		"status": true,
		"data":   data,
		"error":  nil,
	}
}

func SpotErrorResponse(err error) *fiber.Map {
	return &fiber.Map{
		"status": false,
		"data":   "",
		"error":  err.Error(),
	}
}

 

api/handlers/spot_handler.go

구체적인 handler 함수를 짠다. 처음엔 뼈대만 잡을 것이기 때문에 AddSpot 함수만 넣는다.

package handlers

import (
	"camping-backend-with-go/api/presenter"
	"camping-backend-with-go/pkg/entities"
	"camping-backend-with-go/pkg/spot"
	"errors"
	"github.com/gofiber/fiber/v2"
	"net/http"
)

func AddSpot(service spot.Service) fiber.Handler {
	return func(c *fiber.Ctx) error {
		var requestBody entities.Spot
		err := c.BodyParser(&requestBody)
		if err != nil {
			c.Status(http.StatusBadRequest)
			return c.JSON(presenter.SpotErrorResponse(err))
		}
		if requestBody.Author == "" || requestBody.Title == "" {
			c.Status(http.StatusInternalServerError)
			return c.JSON(presenter.SpotErrorResponse(errors.New(
				"Please specify title and author",
			)))
		}

		result, err := service.InsertSpot(&requestBody)
		if err != nil {
			c.Status(http.StatusInternalServerError)
			return c.JSON(presenter.SpotErrorResponse(err))
		}
		return c.JSON(presenter.SpotSuccessResponse(result))
	}
}

 

 

이제 이 handler를 routes에 연결한다.

api/routes/spot.go

package routes

import (
	"camping-backend-with-go/api/handlers"
	"camping-backend-with-go/pkg/spot"
	"github.com/gofiber/fiber/v2"
)

func SpotRouter(app fiber.Router, service spot.Service) {
	app.Post("/spots", handlers.AddSpot(service))
}

 

 

준비가 되었으니 이제 main.go에서 실행하기만 하면된다.

package main

import (
	"camping-backend-with-go/api/routes"
	"camping-backend-with-go/pkg/entities"
	"camping-backend-with-go/pkg/spot"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"log"
	"os"

	"github.com/gofiber/fiber/v2"
)

func main() {
	db := databaseConnection()

	spotRepo := spot.NewRepo(db)
	spotService := spot.NewService(spotRepo)

	app := fiber.New()
	app.Use(cors.New())

	v1 := app.Group("/v1")
	routes.SpotRouter(v1, spotService)
	log.Fatal(app.Listen(":3000"))
}

func databaseConnection() *gorm.DB {
	db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})

	if err != nil {
		log.Fatal("Failed to connect to database. \n", err)
		os.Exit(2)
	}

	log.Println("connected")
	err = db.AutoMigrate(&entities.Spot{})
	if err != nil {
		log.Println(err.Error())
	}

	return db
}

 

DB Setting은 나중에 하기로하고, 지금은 sqlite로 간단하게 진행한다.

air로 실행하자.

 

$ air
  __    _   ___  
 / /\  | | | |_) 
/_/--\ |_| |_| \_ v1.52.3, built with Go go1.23.0

watching .
watching api
watching api/handlers
watching api/presenter
watching api/routes
watching pkg
watching pkg/entities
watching pkg/spot
!exclude tmp
building...
running...
2024/11/24 22:47:52 connected

 ┌───────────────────────────────────────────────────┐ 
 │                   Fiber v2.52.5                   │ 
 │               http://127.0.0.1:3000               │ 
 │       (bound on host 0.0.0.0 and port 3000)       │ 
 │                                                   │ 
 │ Handlers ............. 2  Processes ........... 1 │ 
 │ Prefork ....... Disabled  PID ............. 92077 │ 
 └───────────────────────────────────────────────────┘

 

postman에서 post요청을 날려보자.

 

 

db에서 확인하면 예쁘게 들어간 것을 확인할 수 있다.

 

 

개발의 뼈대가 만들어졌으니 이제 git에 push하고 나머지 부분은 완료하면 될 것 같다.

'devops > go' 카테고리의 다른 글

go fiber에 swagger를 붙여보자.  (0) 2024.11.27
Json Web Token  (0) 2024.11.26
Clean Architecture with go (Feat. fiber)  (1) 2024.11.25
API(Get List)  (0) 2024.11.24
go fiber를 배워보자.  (30) 2024.11.22
'devops/go' 카테고리의 다른 글
  • Json Web Token
  • Clean Architecture with go (Feat. fiber)
  • API(Get List)
  • go fiber를 배워보자.
꼬락이
꼬락이
ggorockee 님의 블로그 입니다.
  • 꼬락이
    꼬락이의 개발일지
    꼬락이
  • 전체
    오늘
    어제
    • 분류 전체보기 (30)
      • devops (28)
        • aws (0)
        • minikube (18)
        • go (10)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    istio
    repository
    k8s
    Github
    Teleport
    GO
    Gorm
    JWT
    aws
    systemd
    EC2
    yq
    SWAGGER
    Minikube
    Github action
    port-forwarding
    db 우회
    CICD
    Kubernetes
    cert-manager
    쿠버네티스
    golang
    ArgoCD
    rds
    Clean Architecture
    DB 연결
    clean-archtiecture
    argoc
    CI
    helm
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
꼬락이
clean-architecture 구성
상단으로

티스토리툴바