Gin 사용해보기
2019-03-01 13:02:02

설치

1
go get -u github.com/gin-gonic/gin

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package main

import (
"fmt"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
)

func main() {

// router := gin.Default() // default로 해도 기본적인건 다 된다

router := gin.New() // 커스텀을 하고 싶으면 이걸로.

router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { // 커스텀 로그 (아파치에서 출력하는 형식)
return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
param.TimeStamp.Format(time.RFC1123),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
}))

router.Use(gin.Recovery()) // go panic -> recover 하는 미들웨어.

router.LoadHTMLGlob("view/*") // view 폴더 설정

// METHOD GET
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{ // Go로 HTMl 자주 뿌리진 않겟지만 쓰려면 이렇게.. view에서 읽을 땐 html 참고, 템플릿 엔진은 핸들바랑 비슷 (.빼고)
"message": "Golang",
})

/*
http 패키지에 상태를 나타내는 변수 모음 몇가지만.
http.StatusOK = 200
http.StatusBadRequest = 400
http.StatusForbidden = 403
http.StatusNotFound = 404
http.StatusInternalServerError = 500
http.StatusBadGateway = 502
*/
})

// 리디렉션.
router.GET("/re", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://localhost:3000/")
})

// 라우팅을 그룹으로 묶을 수 있다. 버전별 API 만들 때 좋은듯.
v1 := router.Group("/v1")
{
v1.GET("/path/:param", readPathParam)
v1.GET("/query", getQueryString)
v1.POST("/login", loginV1)
}

// version v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginV2)
}

// router.Run(":3000") // 기본 실행? 안의 인자는 포트번호.

server := &http.Server{ // http 설정을 커스텀하고 싶으면 요렇게.
Addr: ":3000", // port
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}

server.ListenAndServe() // http config 설정 후 기동.
}

/*
METHOD GET, URL path를 파라미터로 쓰는 경우.
특이하게 path param이 비어 있으면 자동으로 403으로 응답한다. 예외 처리를 안해도 됨.
*/
func readPathParam(c *gin.Context) {
param := c.Param("param")

c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": param,
})
}

// 쿼리스트링
func getQueryString(c *gin.Context) {
id := c.Query("id") // 원하는 쿼리스트링 값 읽기
isGuest := c.DefaultQuery("isGuest", "false") // 쿼리스트링이 비엇을 시 기본 값 대체하는 법 따로 조건처리 안해도 되는군..

if len(id) == 0 { // 문자열로 들어오기 땜에 nil과 비교가 안된다.. 길이로 비교해야 함..
c.JSON(http.StatusBadRequest, gin.H{
"code": 403,
"message": "parameter check",
})
return // return을 명시한 이유는 여기서 멈추기 위해.. 안 그러면 아래 응답을 이어서 보내버린다.. 나머지 return도 마찬가지.
}

data := map[string]interface{}{
"id": id,
"isGuest": isGuest,
}

c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "success",
"data": data,
})

}

// User - 구조체
type User struct {
ID string `json:"id" binding:"required"`
Name string `json:"name" binding:"required"`
Phone string `json:"phone"`
}

// User2 - 구조체
type User2 struct {
ID string `json:"id"`
Name string `json:"name"`
Phone string `json:"phone"`
}

// METHOD POST 인 경우.
func loginV1(c *gin.Context) {
var params User // 위에 선언한 Test 구조체임.

if err := c.ShouldBindJSON(&params); err != nil { // 바인딩할 떄 required에 빈 값이 드러온 경우.
c.JSON(http.StatusBadRequest, gin.H{
"code": 403,
"message": "parameter check",
})

log.Print(err.Error())

return
}

fmt.Println("params", params)

c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "success",
"version": "v1",
})
}

func loginV2(c *gin.Context) {
var params User2 // 위에 선언한 Test 구조체임.

c.BindJSON(&params) // 바인딩을 안할 시 body json 받는 법.

fmt.Println("params", params)

c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "success",
"version": "v2",
})
}
Prev
2019-03-01 13:02:02
Next