Go 웹 개발 완벽 가이드 | Gin·GORM·JWT·Middleware·성능 최적화
이 글의 핵심
Go로 고성능 웹 API를 구축하는 완벽 가이드. Gin 프레임워크, GORM, JWT 인증, Middleware, 동시성, 성능 최적화까지 실전 예제로 정리. Go·Golang·Gin 중심으로 설명합니다. Start now.
이 글의 핵심
Go로 고성능 웹 API를 구축하는 완벽 가이드입니다. Gin 프레임워크, GORM, JWT 인증, Middleware, 동시성, 성능 최적화까지 실전 예제로 정리했습니다.
실무 경험 공유: Node.js API를 Go로 재작성하면서, 응답 속도를 5배 향상시키고 메모리 사용량을 70% 줄인 경험을 공유합니다.
들어가며: “Node.js가 느려요”
실무에서 마주치는 문제들
CPU 집약적 작업이 느려요
Node.js는 싱글 스레드입니다. Go는 고루틴으로 병렬 처리합니다. 메모리를 너무 많이 써요
Node.js는 메모리 사용량이 큽니다. Go는 효율적입니다. 타입 안전성이 부족해요
JavaScript는 런타임 에러가 많습니다. Go는 컴파일 타임에 잡습니다.
1. Go란?
핵심 특징
Go (Golang)는 Google이 만든 시스템 프로그래밍 언어입니다. 주요 장점
-
빠른 성능: C/C++에 근접
-
동시성: 고루틴과 채널
-
간단한 문법: 배우기 쉬움
-
빠른 컴파일: 대규모 프로젝트도 빠름
-
단일 바이너리: 배포 간편 성능 비교
-
Node.js: 5,000 req/sec
-
Python: 2,000 req/sec
-
Go: 20,000 req/sec
2. 설치
터미널에서 다음 명령어를 실행합니다.
# Windows (Chocolatey)
choco install golang
# macOS
brew install go
# 확인
go version
3. Gin 프레임워크
설치
go mod init myapp
go get -u github.com/gin-gonic/gin
기본 서버
// main.go
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Hello World",
})
})
r.GET("/users/:id", func(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{
"user_id": id,
})
})
r.Run(":8080")
}
4. GORM (ORM)
설치
go get -u gorm.io/gorm
go get -u gorm.io/driver/postgres
모델 정의
// models/user.go
// 패키지 선언
package models
import "gorm.io/gorm"
type User struct {
gorm.Model
Name string `json:"name"`
Email string `json:"email" gorm:"uniqueIndex"`
Age int `json:"age"`
}
DB 연결
// db/db.go
package db
import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
"myapp/models"
)
var DB *gorm.DB
func Connect() {
dsn := "host=localhost user=postgres password=secret dbname=mydb port=5432"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("Failed to connect to database")
}
db.AutoMigrate(&models.User{})
DB = db
}
5. CRUD API
// main.go
package main
import (
"myapp/db"
"myapp/models"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
db.Connect()
r := gin.Default()
// 모든 사용자 조회
r.GET("/users", func(c *gin.Context) {
var users []models.User
db.DB.Find(&users)
c.JSON(http.StatusOK, users)
})
// 단일 사용자 조회
r.GET("/users/:id", func(c *gin.Context) {
var user models.User
if err := db.DB.First(&user, c.Param("id")).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
c.JSON(http.StatusOK, user)
})
// 사용자 생성
r.POST("/users", func(c *gin.Context) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db.DB.Create(&user)
c.JSON(http.StatusCreated, user)
})
// 사용자 업데이트
r.PUT("/users/:id", func(c *gin.Context) {
var user models.User
if err := db.DB.First(&user, c.Param("id")).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db.DB.Save(&user)
c.JSON(http.StatusOK, user)
})
// 사용자 삭제
r.DELETE("/users/:id", func(c *gin.Context) {
if err := db.DB.Delete(&models.User{}, c.Param("id")).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "User deleted"})
})
r.Run(":8080")
}
6. JWT 인증
설치
go get -u github.com/golang-jwt/jwt/v5
JWT 생성
// auth/jwt.go
package auth
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("your-secret-key")
type Claims struct {
UserID uint `json:"user_id"`
Email string `json:"email"`
jwt.RegisteredClaims
}
func GenerateToken(userID uint, email string) (string, error) {
claims := Claims{
UserID: userID,
Email: email,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
func ValidateToken(tokenString string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, err
}
Middleware
// middleware/auth.go
package middleware
import (
"myapp/auth"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
c.Abort()
return
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
claims, err := auth.ValidateToken(tokenString)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
c.Abort()
return
}
c.Set("user_id", claims.UserID)
c.Set("email", claims.Email)
c.Next()
}
}
사용
// 실행 예제
r.GET("/protected", middleware.AuthMiddleware(), func(c *gin.Context) {
userID := c.GetUint("user_id")
c.JSON(http.StatusOK, gin.H{
"message": "Protected route",
"user_id": userID,
})
})
7. 동시성
고루틴
func processUsers(users []User) {
for _, user := range users {
go func(u User) {
// 비동기 처리
sendEmail(u.Email)
}(user)
}
}
채널
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// 3개의 워커 시작
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 작업 전송
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
// 결과 수신
for a := 1; a <= 9; a++ {
<-results
}
}
8. 배포
Docker
# Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o main .
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD [./main]
docker build -t myapp .
docker run -p 8080:8080 myapp
정리 및 체크리스트
핵심 요약
- Go: 빠르고 간단한 시스템 언어
- Gin: 고성능 웹 프레임워크
- GORM: 강력한 ORM
- JWT: 인증 구현
- 고루틴: 동시성 처리
- 단일 바이너리: 배포 간편
구현 체크리스트
- Go 프로젝트 생성
- Gin 서버 구현
- GORM으로 DB 연결
- CRUD API 구현
- JWT 인증 구현
- Middleware 작성
- Docker 배포
같이 보면 좋은 글
이 글에서 다루는 키워드
Go, Golang, Gin, GORM, Backend, REST API, Performance
자주 묻는 질문 (FAQ)
Q. Go vs Node.js, 어떤 게 나은가요?
A. Go가 훨씬 빠르고 메모리 효율적입니다. CPU 집약적 작업은 Go, I/O 집약적 작업은 둘 다 괜찮습니다.
Q. 학습 곡선이 가파른가요?
A. 문법은 간단합니다. 하지만 포인터, 고루틴 등 새로운 개념이 있습니다.
Q. 프론트엔드 개발도 가능한가요?
A. 아니요, Go는 백엔드 전용입니다. 프론트엔드는 JavaScript/TypeScript를 사용하세요.
Q. 프로덕션에서 사용해도 되나요?
A. 네, Google, Uber, Dropbox 등 많은 기업에서 사용합니다.