don't stop believing

[swag] Gin에서 Swagger 사용하기 본문

Golang/Gin

[swag] Gin에서 Swagger 사용하기

Tongchun 2019. 3. 4. 18:44

API 서버를 만드는데있어 문서화는 필수입니다.

Gin에서 Swagger를 사용하는 걸 확인해 보겠습니다.

https://github.com/swaggo/gin-swagger


먼저 Go에서 swag를 사용할 수 있게 source code를 다운로드 합니다.

$ go get -u github.com/swaggo/swag/cmd/swag

swag가 잘 다운로드 돼었는지 확인해 봅니다.

$ ll $GOPATH/src/github.com/swaggo
total 0
drwxr-xr-x   3 tongchunkim  staff    96B  3  4 17:58 .
drwxr-xr-x  30 tongchunkim  staff   960B  3  4 17:58 ..
drwxr-xr-x  34 tongchunkim  staff   1.1K  3  4 17:58 swag

이제 프로젝트 폴더를 하나 만들고 swag init을 해줍니다.

저는 testSwagger라고 폴더를 만들었습니다. 그리고 그 안에 swag init 을 했습니다.

$ mkdir testSwagger && cd testSwagger
$ swag init
2019/03/04 18:10:47 Generate swagger docs....
2019/03/04 18:10:47 Generate general API Info
2019/03/04 18:10:47 create docs.go at  docs/docs.go

swag init을 하면 docs 폴더와 그 하외에 swagger 파일이 생성됩니다.


이제 main package를 만들어 봅니다.

저는 server.go로 만들고 이전에 사용했던 Parameters in path 예제를 그대로 가져다 사용해 만들었습니다. (조금 추가/수정했습니다.)

https://dejavuqa.tistory.com/320?category=320633

package main

import (
	"github.com/gin-gonic/gin"
)

type welcomeModel struct {
	ID   int    `json:"id" example:"1" format:"int64"`
	Name string `json:"name" example:"account name"`
}

func setupRouter() *gin.Engine {

	r := gin.Default()

	r.GET("/welcome/:name", welcomePathParam)

	return r
}

func welcomePathParam(c *gin.Context) {
	name := c.Param("name")
	message := name + " is very handsome!"
	welcomeMessage := welcomeModel{1, message}

	c.JSON(200, gin.H{"message": welcomeMessage})
}

func main() {
	r := setupRouter()

	r.Run() // Listen and Server in 0.0.0.0:8080
}

이제 swagger 연동을 시작하겠습니다.

gin-swagger를 다운로드 합니다.

$ go get -u github.com/swaggo/gin-swagger
$ go get -u github.com/swaggo/gin-swagger/swaggerFiles

다운로드한 package를 server.go의 import에 추가합니다.

그리고 swag init으로 생성된 docs package도 추가해 줍니다. docs package를 추가하려면 GOPATH의 src 하위 경로로 잡아주면 됩니다.


import (

"github.com/gin-gonic/gin"


ginSwagger "github.com/swaggo/gin-swagger"

swaggerFiles "github.com/swaggo/gin-swagger/swaggerFiles"

"github.com/dejavuwing/testSwagger/docs"

)

그리고 setupRouter() 함수에 swagger route를 추가해 줍니다.

r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

이제 welcomePathParma() 함수 위에 annotation을 아래와 같이 추가합니다.

// Welcome godoc

// @Summary Summary를 적어 줍니다.

// @Description 자세한 설명은 이곳에 적습니다.

// @name get-string-by-int

// @Accept  json

// @Produce  json

// @Param name path string true "User name"

// @Router /welcome/{name} [get]

// @Success 200 {object} welcomeModel 

위에서 설명한 코드를 추가한 전체 코드는 아래와 같습니다.

package main import ( "github.com/gin-gonic/gin" "github.com/dejavuwing/testSwagger/docs" ginSwagger "github.com/swaggo/gin-swagger" swaggerFiles "github.com/swaggo/gin-swagger/swaggerFiles" ) type welcomeModel struct { ID int `json:"id" example:"1" format:"int64"` Name string `json:"name" example:"account name"` } func setupRouter() *gin.Engine { r := gin.Default() r.GET("/welcome/:name", welcomePathParam) r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) return r } // Welcome godoc // @Summary Summary를 적어 줍니다. // @Description 자세한 설명은 이곳에 적습니다. // @name get-string-by-int // @Accept json // @Produce json // @Param name path string true "User name" // @Router /welcome/{name} [get] // @Success 200 {object} welcomeModel func welcomePathParam(c *gin.Context) { name := c.Param("name") message := name + " is very handsome!" welcomeMessage := welcomeModel{1, message} // welcomeMessage := model.User{ID: 1, Name: name} c.JSON(200, gin.H{"message": welcomeMessage}) } func main() { // programatically set swagger info docs.SwaggerInfo.Title = "Swagger Example API" docs.SwaggerInfo.Description = "This is a sample server for Swagger." docs.SwaggerInfo.Version = "1.0" docs.SwaggerInfo.Host = "petstore.swagger.io" docs.SwaggerInfo.BasePath = "/v2" r := setupRouter() r.Run() // Listen and Server in 0.0.0.0:8080 }

swagger로 변환하기 위해 swag init을 한번 더 해줍니다.

annotation으로된 swagger 문서가 변경되거나 할 경우 swag init을 다시 해줘야 합니다.

$ swag init
2019/03/05 17:52:14 Generate swagger docs....
2019/03/05 17:52:14 Generate general API Info
2019/03/05 17:52:14 create docs.go at  docs/docs.go

이제 server.go를 실행해 봅니다.

$ go run server.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    /welcome/:name            --> main.welcomePathParam (3 handlers)
[GIN-debug] GET    /swagger/*any             --> github.com/swaggo/gin-swagger.WrapHandler.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080

만약 server.go를 실행했을때 아래와 같은 메시지가 나온다면 github.com/alecthomas/template package를 다운받아야 합니다.

$ go run server.go 
docs/docs.go:10:2: cannot find package "github.com/alecthomas/template" in any of:
	/usr/local/opt/go/libexec/src/github.com/alecthomas/template (from $GOROOT)
	/Users/tongchunkim/go/src/github.com/alecthomas/template (from $GOPATH)

swag init으로 생성된 docs에서 github.com/alecthomas/template를 사용하고 있습니다.

$ go get -u github.com/alecthomas/template

정상적으로 server.go가 실행되었다면 아래 경로로 swagger를 호출해 봅니다.

http://localhost:8080/swagger/index.html


그런데 Errors 메시지가 나오네요.

우선 GET /welcome/{name}을 클릭해 봅니다.

annotation으로 작성한 문서가 잘 보이네요.


Errors 메세지를 확인해 보겠습니다.

struct로 작성된 welcomeModel이 문제인것 같습니다.

이걸 해결하기 위해 Web Server (server.go)의 구조를 변경하겠습니다. Model을 별도의 package로 만들어 주겠습니다.


testSwagger폴더 아래 model 이란 폴더를 만들어 주고 그 안에 user.go를 만들어 줍니다.

tree 명령으로 확인하면 아래와 같습니다.

$ tree
.
├── docs
│   ├── docs.go
│   └── swagger
│       ├── swagger.json
│       └── swagger.yaml
├── model
│   └── user.go
└── server.go

3 directories, 5 files

user.go 파일안에 user 데이터를 담을 수 있는 struct를 만들어 줍니다.

package 명은 model로 해줍니다.

package model

type User struct {
	ID   int    `json:"id" example:"1"`
	Name string `json:"name" example:"user name"`
}

이제 server.go에서 model package를 import하고 model.User에 데이터를 담아 json 형태로 response 해 줍니다.

그리고 swagger annotation 중 @Success 부분을 아래와 같이 변경합니다.

// @Success 200 {object} model.User

수정한 server.go 코드는 아래와 같습니다.

package main

import (
	"github.com/gin-gonic/gin"

	"github.com/dejavuwing/testSwagger/docs"
	"github.com/dejavuwing/testSwagger/model"

	ginSwagger "github.com/swaggo/gin-swagger"
	swaggerFiles "github.com/swaggo/gin-swagger/swaggerFiles"
)

func setupRouter() *gin.Engine {

	r := gin.Default()

	r.GET("/welcome/:name", welcomePathParam)
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	return r
}

// Welcome godoc
// @Summary Summary를 적어 줍니다.
// @Description 자세한 설명은 이곳에 적습니다.
// @name get-string-by-int
// @Accept  json
// @Produce  json
// @Param name path string true "User name"
// @Router /welcome/{name} [get]
// @Success 200 {object} model.User
func welcomePathParam(c *gin.Context) {
	name := c.Param("name")
	welcomeMessage := model.User{ID: 1, Name: name}

	c.JSON(200, gin.H{"message": welcomeMessage})
}

func main() {

	// programatically set swagger info
	docs.SwaggerInfo.Title = "Swagger Example API"
	docs.SwaggerInfo.Description = "This is a sample server for Swagger."
	docs.SwaggerInfo.Version = "1.0"
	docs.SwaggerInfo.Host = "petstore.swagger.io"
	docs.SwaggerInfo.BasePath = "/v2"

	r := setupRouter()

	r.Run() // Listen and Server in 0.0.0.0:8080
}

코드에 수정이 있으니 다시 swag init을 해줍니다.

$ swag init
2019/03/05 18:23:27 Generate swagger docs....
2019/03/05 18:23:27 Generate general API Info
2019/03/05 18:23:27 Generating model.User
2019/03/05 18:23:27 create docs.go at  docs/docs.go

이전에는 없었던 model.User도 Generating되는게 보입니다.

 

server.go를 실행해 줍니다.

$ go run server.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    /welcome/:name            --> main.welcomePathParam (3 handlers)
[GIN-debug] GET    /swagger/*any             --> github.com/swaggo/gin-swagger.WrapHandler.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080

swagger를 다시 실행해 보겠습니다.

Errors 메시지가 없어지고 Models package의 model.User struct가 새로 보입니다.

여기까지가 golang (gin)에서 swagger를 사용하는 방법이었습니다.

세부적인 annotation은 아래 설명 페이지나 example 에서 확인할 수 있습니다.


https://github.com/swaggo/swag#api-operation

https://github.com/swaggo/swag/tree/master/example


'Golang > Gin' 카테고리의 다른 글

Model binding and validation  (0) 2019.03.06
mysql curd (with Gin)  (0) 2019.03.06
Grouping routes  (0) 2019.03.04
Upload files  (0) 2019.02.27
Map as querystring or postform parameters  (0) 2019.02.27
Comments