Golang Gin Gonic - 3. Post files to API server
간단한 API 서버를 제외하고는 웹서비스의 전형적인 HTTP API server를 실무에서 개발한 적이 없다. 유튜브에서 Golang의 대표적인 web framework인 Gin을 이용한 좋은 강좌를 만나 이를 하나씩 따라하려고 한다.
세 번째로 사용자의 아바타 파일을 올리면 그것을 저장할 수 있도록 하면서, uri와 form도 복습을 해보겠다
Playlist: Rest API in Golang using Gin Gonic: https://bit.ly/3hsZKbv
YouTube: Post files to API server using Gin in Golang: https://youtu.be/M5KhqwOrBGc
구현해본 GitHub repo: https://github.com/nicewook/gin-gonic-study
이번 블로그 포스팅 소스코드: https://github.com/nicewook/gin-gonic-study/tree/main/post-file-3
구현 코드
코드 자체는 매우 간단하다.
1. User 구조체는 Avatar라는 필드를 가진다.
2. /user/:id 라는 enpoint로 들어오는 PUT request 에 대해 putUserHandle() 핸들러가 처리를 해준다.
3. 순서대로 하나씩 처리를 하는데
1) ShouldBind() 메서드로 name과 email 데이터를 받고, 이 단계까지의 user 인스턴스의 값을 출력해본다
2) ShoudBindUri() 메서드로 id를 받고, 출력한다
3) SaveUploadedFile() 메서드로 파일을 저장준 다음, PUT request를 받아서 정리한 user 인스턴스를 response 해준다.
type User struct {
ID int `uri:"id"`
Name string `form:"name"`
Email string `form:"email"`
Avatar *multipart.FileHeader `form:"avatar"`
}
func putUserHandle(c *gin.Context) {
var user User
if err := c.ShouldBind(&user); err != nil {
log.Println("err: ", err)
c.AbortWithStatus(http.StatusBadRequest)
}
log.Printf("user: %+v", user)
if err := c.ShouldBindUri(&user); err != nil {
log.Println("err: ", err)
c.AbortWithStatus(http.StatusBadRequest)
}
log.Printf("user: %+v", user)
if err := c.SaveUploadedFile(user.Avatar, "assets/"+user.Avatar.Filename); err != nil {
log.Println("err: ", err)
c.AbortWithStatus(http.StatusBadRequest)
}
log.Printf("user: %+v", user)
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"data": user,
})
}
func newServer() *gin.Engine {
r := gin.Default()
r.PUT("/user/:id", putUserHandle)
return r
}
func main() {
newServer().Run()
}
Postman 테스트
위 프로그램을 실행시키고 Postman을 이용하여 PUT request를 보내면 아래에 제대로 회신이 오는 것을 알 수 있다.
참고. curl로도 동일 명령을 보낼 수 있다.
curl --location --request PUT 'http://localhost:8080/user/100' --form 'name="hsjeong"' --form 'email="hsjeong@a.com"' --form 'avatar=@"/C:/Users/hsjeong/Pictures/j.jpg"' |
Server 로그
로그를 보면 이해가 쉬울 것이다.
1) ShouldBind() 메서드가 실행되어 Name, Email, Avatar 필드가 채워졌다
2) ShoudBindUri() 메서드가 실행되어 ID 필드가 채워졌다.
3) SaveUploadedFile() 메서드가 실행되며 파일이 저장되었다.
$ go run .
[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] PUT /user/:id --> main.putUserHandle (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
2021/10/01 15:54:54 user: {ID:0 Name:hsjeong Email:hsjeong@a.com Avatar:0xc000091090}
2021/10/01 15:54:54 user: {ID:100 Name:hsjeong Email:hsjeong@a.com Avatar:0xc000091090}
2021/10/01 15:54:54 user: {ID:100 Name:hsjeong Email:hsjeong@a.com Avatar:0xc000091090}
[GIN] 2021/10/01 - 15:54:54 | 200 | 467.8µs | ::1 | PUT "/user/100"