Go 1.21 제네릭 적용 후기: API 응답 래퍼 리팩토링
배경
사내 마이크로서비스 API 게이트웨이를 Go로 운영 중인데, 각 서비스마다 비슷한 응답 래핑 코드가 반복되고 있었다. Go 1.18에서 제네릭이 도입됐지만 프로덕션 적용은 미뤄왔는데, 1.21이 안정화되면서 본격적으로 도입해봤다.
기존 코드
type UserResponse struct {
Data User `json:"data"`
Message string `json:"message"`
}
type ProductResponse struct {
Data Product `json:"data"`
Message string `json:"message"`
}
func handleUserAPI(w http.ResponseWriter, r *http.Request) {
user := getUserFromDB()
resp := UserResponse{Data: user, Message: "success"}
json.NewEncoder(w).Encode(resp)
}
각 엔드포인트마다 Response 구조체를 만들고 있었다.
제네릭 적용
type APIResponse[T any] struct {
Data T `json:"data"`
Message string `json:"message"`
Error string `json:"error,omitempty"`
}
func respondJSON[T any](w http.ResponseWriter, data T, message string) {
resp := APIResponse[T]{
Data: data,
Message: message,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
}
func handleUserAPI(w http.ResponseWriter, r *http.Request) {
user := getUserFromDB()
respondJSON(w, user, "success")
}
결과
- 30개 넘는 Response 구조체 제거
- 타입 안정성 유지하면서 보일러플레이트 코드 80% 감소
- 에러 핸들링도 제네릭 함수로 통일
컴파일 타임은 약간 늘었지만 실행 성능은 차이 없었다. 팀 내에서도 코드 가독성이 개선됐다는 반응이 좋았다. 다음에는 repository 레이어도 제네릭으로 리팩토링할 계획이다.