이 주제를 선정한 이유
내 토이프로젝트에서 트랜잭션을 만들었는데 필요한 곳이 여러 곳이 있어 재사용성에 용이하도록 미들웨어로 만들고자 하였다.
아래는 내가 사용하는 go의 orm인 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())
// 나머지 로직
}
}
이런 패턴은 미들웨어가 추가적인 설정이나 의존성이 필요할 때 자주 사용된다.
도움을 주신 분들
[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
'tech' 카테고리의 다른 글
go 포인터 c 포인터와 무슨차이 (0) | 2025.01.14 |
---|---|
go 템플릿 주요 문법 (0) | 2025.01.09 |
go ORM ent 를 사용하여 maria db에 연결해보자 (0) | 2024.12.09 |
라우팅에 특화된 go프레임워크 - gollia/mux vs Gin framework (1) | 2024.12.05 |
Go의 특이한 예외처리 방식 [1편] (0) | 2024.12.02 |