My Melody Crying /윤잡스
윤잡스
카테고리
작성일
2024. 12. 18. 16:25
작성자
네수

 

이 주제를 선정한 이유

 

 

내 토이프로젝트에서 트랜잭션을 만들었는데 필요한 곳이 여러 곳이 있어 재사용성에 용이하도록 미들웨어로 만들고자 하였다.

 

아래는 내가 사용하는 go의 orm인 ent 의 공식 docs에서 찾은 '트랜잭션' 예제이다.

 

ent docs

 

 

 

내 목표는 "트랜잭션의 재사용성을 위해 미들웨어로 만들어 사용하기" 이다.

 

하지만, 이 웹에서의 예제로는 미들웨어로서의 기능을 하지 못한다.

 

왜냐면  gin 프레임워크에서는 미들웨어 함수로서 정의하려면, 매개변수로 Context 객체를 받아야 하기 때문이다.

 

왜인지 궁금하여 ➡️ https://pkg.go.dev/github.com/gin-gonic/gin#Context 여기에서 찾아봤다.

더보기

Context는 Gin에서 가장 중요한 부분입니다. 이를 통해 미들웨어 간에 변수를 전달하고, 흐름을 관리하고, 요청의 JSON 유효성을 검사하고, 예를 들어 JSON 응답을 렌더링할 수 있습니다.

 

 

 

 

🤔그럼 ent 트랜잭션 예제 코드를 응용하여 어떻게 미들웨어로 만들 수 있을까? 

 

 

gin docs에서 제공하는 custom middleware 예시를 먼저 살펴보자.

 

이 예제에서 보면 return func(c *gin.Context) .. 어쩌고 Context 객체를 매개변수로 받은 걸 볼 수 있는데

형태가 좀 특이하다.

 

func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()

		// Set example variable
		c.Set("example", "12345")

		// before request

		c.Next()

		// after request
		latency := time.Since(t)
		log.Print(latency)

		// access the status we are sending
		status := c.Writer.Status()
		log.Println(status)
	}
}

func main() {
	r := gin.New()
	r.Use(Logger())

	r.GET("/test", func(c *gin.Context) {
		example := c.MustGet("example").(string)

		// it would print: "12345"
		log.Println(example)
	})

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

 

나는 뭐든 알고 쓰자는 주의여서, 검색에 나섰다.

 

 

이 패턴은 제목에서 스포했듯이, 클로저 패턴 이라고 한다.

 

클로저 패턴이란 :  함수 안에서 함수를 선언 및 정의할 수 있고, 바깥쪽 함수에 선언된 변수에도 접근할 수 있는 함수

클로저 개념은 🔗 https://pyrasis.com/book/GoForTheReallyImpatient/Unit25

 

 

1. 일반적인 Gin 미들웨어 :

func NormalMiddleware(c *gin.Context) {
	//미들웨어 로직
}

 

2. 데이터베이스 클라이언트가 필요한 경우 :

//  x 이렇게 하면 안됨
func WrongMiddleware(c *gin.Context) {
	//client(ent orm의 client)는 어디서 가져오지..?🤔
    // ent orm의 client는 모든 엔트 빌더를 보유하는 클라이언트임
    // 나머지 로직
}

 

 

3. 클로저를 사용한 해결방법 :

func TransactionMiddleware(client *ent.Client) gin.Handlefunc {
	// 외부에서 client를 받아서
    return func(c *gin.Context) {
    // 내부 함수에서 client 사용가능!
    tx, err := client.Tx(c.Request.Context())
    // 나머지 로직
    }
}

 

 

이런 패턴은 미들웨어가 추가적인 설정이나 의존성이 필요할 때 자주 사용된다. 

 

 

 

 

 


도움을 주신 분들 

 

https://velog.io/@fudoge/Gin-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4%EB%A5%BC-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0-feat.-json-%EB%B0%94%EB%94%94-%ED%8C%8C%EC%8B%B1%ED%95%98%EA%B8%B0

 

[Gin] 미들웨어를 설정하기 (feat. json 바디 파싱하기)

요청-응답의 사이에 있어서 미들웨어라고 불린다.미들웨어는 요청-응답 사이클 사이에서 추가적인 기능을 부여할 수 있고, 본 핸들러로 넘어가기 전에 전처리 과정을 거칠 수도 있다.요청문을

velog.io

 

 

https://gin-gonic.com/docs/examples/custom-middleware/

 

Custom Middleware

func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // Set example variable c.Set("example", "12345") // before request c.Next() // after request latency := time.Since(t) log.Print(latency) // access the status we are sending stat

gin-gonic.com

 

https://limm-jk.tistory.com/77