1월부터 하는 Kubernetes에서 실제로 서비스를 구축하기 위해 간단한 마이크로 서비스를 만들어 보고 있다. 주로 Node.js로 하는 게 편하지만 다른 언어도 배워보고 싶어서 Golang을 선택했다. 아주 간단한 API 서버라서 웹 프레임워크가 필요했는데 Go 언어에 대해 아는 게 없어서 좀 찾아봤다.
Top 6 web frameworks for Go as of 2017같은 글을 참고했는데 본격적으로 사용해 보지 않으면 감이 잘 안와서 선택이 쉽지는 않았다. 웹 MVC 프레임워크로는 beego나 Buffalo가 있었지만 주로 마이크로 웹 프레임워크를 더 선호하는 편이라서 Gin이나 echo, Iris에 관심이 갔다.
Go My Way #1 - 웹 프레임워크를 보다 보니 일부러 프로젝트가 활발한 것처럼 보이려고 속이던 행동이 발견된 Iris는 일찌감치 제외하고 Gin와 echo 중에서 고민하다가 크게 차이는 없는 것 같아서(특히 지금 내 용도에서는...) 좀 더 스타가 많은 Gin을 선택했다.
Gin
저장소의 README에 나온 내용대로 main.go
파일을 생성한다.
// main.go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
Go 언어에서 dep으로 의존성 관리를 하고 있어서 dep을 초기화한다.
$ dep init
초기화 후 만들어진 Gopkg.toml
파일에 gin
을 사용하기 위해 다음 내용을 추가한다.
[[constraint]]
name = "github.com/gin-gonic/gin"
branch = "master"
이제 추가한 의존성을 설치한다.
$ dep ensure
의존성 설치도 완료되었으면 Hello World 식 예제 애플리케이션을 실행할 수 있다.
$ go run main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /ping --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
Gin 서버가 http://localhost:8080에 떴으므로 이 서버에 요청을 보내면 정상적으로 뜬 것을 확인할 수 있다.
$ curl -i http://localhost:8080/ping
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 29 Apr 2018 16:45:36 GMT
Content-Length: 18
{"message":"pong"}
실제 웹 애플리케이션을 작성하려면 데이터베이스 라이브러리도 필요하고 프로젝트 폴더 구조도 만들어야 하지만 이 글에서는 Gin에 대한 설정만 얘기하고 있으므로 간단히 Gin의 라우팅만 살펴보자.
// main.go
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
v1 := r.Group("/v1")
{
v1.GET("/health", health)
v1.POST("/signup", signup)
v1.POST("/login", login)
}
r.Run()
}
func health(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
}
func signup(c *gin.Context) {
c.JSON(http.StatusCreated, gin.H{
"message": "signed up",
})
}
func login(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "logged in",
})
}
보통 API 서버는 URL에 접두사가 붙으므로 r.Group("/v1")
을 사용하면 반복해서 사용하지 않아도 된다. 위 설정은 http://localhost:3000/v1/health
로 요청을 받게 된다. 상태 코드를 숫자로 적어도 되지만 net/http에서 상수를 가져와서 HTTP 상태 코드로 사용할 수 있다.
$ PORT=3000 go run main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /v1/health --> main.health (3 handlers)
[GIN-debug] POST /v1/signup --> main.signup (3 handlers)
[GIN-debug] POST /v1/login --> main.login (3 handlers)
[GIN-debug] Environment variable PORT="3000"
[GIN-debug] Listening and serving HTTP on :3000
그리고 gin은 기본 포트로 8080
을 사용하지만 PORT
환경변수를 지정하면 해당 포트로 서버를 실행하게 된다.
Comments