Gin 기초 #1 시작과 첫 서버
이 시리즈는 Go(고 언어)로 웹 API를 만들고 싶은 분을 위한 7편짜리 입문 강좌입니다. Go 기초 시리즈에서 문법을 익혔다면, 이제 그 문법으로 실제 HTTP 서버를 짜는 단계입니다.
- #1 시작과 첫 서버 ← 이번 글
- #2 라우팅과 핸들러
- #3 요청 바인딩과 검증
- #4 응답 처리 — JSON, 상태 코드, 에러
- #5 미들웨어
- #6 데이터베이스 연동 (GORM)
- #7 프로젝트 구조와 미니 REST API
이번 글은 표준 라이브러리 net/http만으로 부족한 점을 짚고, Gin을 설치해 첫 서버를 띄우는 곳까지 갑니다.
Gin은 무엇인가? #
Gin은 Go에서 가장 널리 쓰이는 웹 프레임워크입니다. 정확히는 HTTP 라우터와 미들웨어 위주의 가벼운 프레임워크입니다. 표준 라이브러리 net/http 위에 얇게 올라가 있어서, Go의 기본 동작을 거의 그대로 유지하면서 반복 작업만 덜어 줍니다.
핵심 특징은 다음과 같습니다.
- 빠른 라우팅 — radix tree 기반 라우터로 경로 매칭이 빠름
- 간결한 핸들러 —
gin.Context하나로 요청 읽기와 응답 쓰기를 처리 - 미들웨어 체인 — 로깅, 복구, 인증 같은 공통 처리를 깔끔하게 연결
- 편의 기능 — JSON 바인딩, 검증, 파일 응답이 기본 제공
Go 진영에서 사실상 표준에 가까운 선택지라, 자료와 예제가 가장 많습니다. 입문 단계에서 막혔을 때 검색으로 답을 찾기 쉽다는 점도 큰 장점입니다.
net/http만으로는 왜 부족한가? #
Go는 표준 라이브러리만으로도 HTTP 서버를 짤 수 있습니다. Go 1.22부터는 net/http의 ServeMux가 메서드와 경로 패턴 매칭까지 지원합니다. 그래서 간단한 서버라면 외부 프레임워크가 전혀 필요 없습니다.
그런데 실제 API를 만들다 보면 같은 코드를 계속 반복하게 됩니다.
package main
import (
"encoding/json"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /ping", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"message": "pong"})
})
http.ListenAndServe(":8080", mux)
}JSON 하나 내보내는 데도 헤더 설정, 상태 코드, 인코딩을 매번 직접 써야 합니다. 경로 파라미터를 읽고, 요청 본문을 검증하고, 여러 핸들러에 공통 로직을 거는 작업까지 더하면 코드가 금방 장황해집니다.
Gin은 바로 이 반복을 줄여 줍니다. 같은 응답을 Gin으로 쓰면 이렇게 됩니다.
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
})c.JSON 한 줄이 헤더 설정, 상태 코드, 인코딩을 한꺼번에 처리합니다. 차이는 작아 보이지만, 엔드포인트가 수십 개로 늘어나면 누적된 차이가 큽니다.
다른 Go 웹 프레임워크와 비교 #
Gin 말고도 선택지가 있으니, 대략적인 위치만 짚어 두겠습니다.
| Gin | Echo | Fiber | Chi | |
|---|---|---|---|---|
| 기반 | net/http | net/http | fasthttp | net/http |
| 성격 | 라우터+미들웨어 | 라우터+미들웨어 | Express 스타일 | 얇은 라우터 |
| 생태계 | 가장 큼 | 큼 | 큼 | 표준 친화 |
| 학습 난이도 | 낮음 | 낮음 | 낮음 | 가장 낮음 |
Echo는 Gin과 거의 비슷한 위치이고, Fiber는 net/http가 아닌 fasthttp 위에 올라가 성능을 더 챙긴 대신 표준 호환성을 일부 포기합니다. Chi는 표준 net/http에 가장 충실한 얇은 라우터입니다. 입문이라면 자료가 가장 많은 Gin으로 시작하고, 필요할 때 다른 선택지를 살펴보는 편을 권합니다.
준비 — Go 모듈 #
Gin은 Go 패키지이므로 Go가 먼저 설치되어 있어야 합니다. 설치가 아직이라면 Go 기초 #1을 먼저 보고 오세요. 이 시리즈는 Go 1.22 이상을 가정합니다.
새 프로젝트를 만들고 모듈을 시작합니다.
mkdir gin-hello
cd gin-hello
go mod init gin-hellogo mod init이 go.mod 파일을 만들고 새 모듈을 시작합니다. 모듈 개념은 Go 기초 시리즈에서 다뤘으니, 여기서는 그대로 진행하겠습니다.
Gin 설치 #
go get으로 Gin을 의존성에 추가합니다.
go get github.com/gin-gonic/gin이 시리즈는 Gin v1.10 기준으로 작성합니다. 설치하면 go.mod에 의존성이 기록되고, go.sum에 체크섬이 남습니다. 둘 다 버전 관리(git)에 포함하세요.
첫 서버 — Hello, Gin #
main.go 파일을 만들어 다음을 적습니다.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
})
r.Run() // 기본 :8080
}실행합니다.
go run main.go서버가 뜨면 다른 터미널에서 요청을 보내 봅니다.
curl http://localhost:8080/ping
# {"message":"pong"}브라우저에서 http://localhost:8080/ping을 열어도 같은 JSON이 보입니다. 첫 Gin 서버가 동작했습니다.
코드 한 줄씩 풀어보기 #
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
})
r.Run()gin.Default()— 라우터(엔진)를 만듭니다. 로깅과 복구 미들웨어가 기본으로 붙어 있습니다.r.GET("/ping", ...)— GET 메서드로/ping경로가 들어오면 실행할 핸들러를 등록합니다.func(c *gin.Context)— 핸들러의 형태입니다. 모든 요청 정보와 응답 기능이gin.Context하나에 담겨 있습니다.c.JSON(...)— 상태 코드와 데이터를 받아 JSON으로 응답합니다.gin.H는map[string]any의 단축 표기입니다.r.Run()— 서버를 시작합니다. 인자를 비우면:8080에서 listen 합니다.r.Run(":3000")처럼 포트를 지정할 수도 있습니다.
상태 코드를 200 같은 숫자 대신 http.StatusOK로 쓴 점에 주목하세요. 의미가 분명해지고, 오타로 잘못된 코드를 넣을 위험이 줄어듭니다. 이 시리즈는 표준 상수를 쓰는 쪽을 따릅니다.
gin.Default() vs gin.New() #
라우터를 만드는 방법은 두 가지입니다.
r := gin.Default() // Logger + Recovery 미들웨어 포함
r := gin.New() // 미들웨어 없는 빈 엔진gin.Default()는 요청 로그를 찍는 Logger와, 핸들러에서 panic이 나도 서버가 죽지 않게 막아 주는 Recovery 미들웨어를 자동으로 붙입니다. 입문 단계에서는 gin.Default()로 충분합니다.
gin.New()는 아무 미들웨어도 없는 빈 엔진입니다. 어떤 미들웨어를 붙일지 직접 통제하고 싶을 때 씁니다. 미들웨어는 #5 미들웨어에서 자세히 다루겠습니다.
릴리스 모드 #
서버를 처음 띄우면 콘솔에 다음 경고가 보입니다.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.Gin은 기본이 debug 모드라, 등록된 라우트 목록 같은 디버그 정보를 출력합니다. 실제 배포 환경에서는 release 모드로 바꿔 불필요한 로그를 줄입니다.
gin.SetMode(gin.ReleaseMode)또는 환경 변수 GIN_MODE=release로도 설정됩니다. 지금은 개발 중이니 debug 모드 그대로 두어도 괜찮습니다. 배포 관련 설정은 중급 시리즈에서 다시 짚겠습니다.
핫 리로드 — 저장하면 자동 재시작 #
코드를 고칠 때마다 go run을 다시 실행하기는 번거롭습니다. air 같은 도구를 쓰면 파일이 바뀔 때마다 자동으로 다시 빌드하고 서버를 재시작해 줍니다.
go install github.com/air-verse/air@latest
air필수는 아니지만, 개발 편의가 크게 올라갑니다. 설치하지 않아도 이 시리즈를 따라가는 데는 지장이 없습니다.
마무리 #
이번 글에서 정리한 내용입니다.
- Gin은
net/http위에 얇게 올라간, Go에서 가장 널리 쓰이는 웹 프레임워크 - 표준 라이브러리만으로도 서버는 되지만, JSON 응답, 검증, 공통 처리의 반복을 Gin이 줄여 줌
- 설치는
go get github.com/gin-gonic/gin, 시리즈는 Gin v1.10 기준 gin.Default()로 라우터를 만들고,r.GET으로 핸들러를 등록,r.Run()으로 시작- 응답은
c.JSON(http.StatusOK, gin.H{...})한 줄 - 상태 코드는
http.StatusOK같은 표준 상수로 - 개발 중 핫 리로드는 air가 편리
다음 글(#2 라우팅과 핸들러)에서는 경로 파라미터와 쿼리 스트링을 읽는 법, 라우터 그룹으로 엔드포인트를 묶는 법을 정리하겠습니다.