swaggo / gin-swagger

gin middleware to automatically generate RESTful API documentation with Swagger 2.0.
MIT License
3.66k stars 266 forks source link

Do not detect handler when the handler under structure #258

Closed tomy128 closed 1 year ago

tomy128 commented 1 year ago

I will put a complete code here for you to reproduce it. thks :-) This is the directory tree:

.
├── Makefile
├── docs
│   ├── docs.go
│   ├── swagger.json
│   └── swagger.yaml
├── go.mod
├── go.sum
└── src
    ├── cmd
    │   └── main.go  # entrance
    └── controller
        ├── api
        │   ├── base_controller.go
        │   └── user_center  # user module
        │       └── user.go  # real controller
        └── router.go  # collection router

cmd/main.go

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    "net/http"
        "swag/src/controller"
)

// @title           MetaQ
// @version         1.0
// @description     xxxxxxx

// @contact.name   hahahah
// @contact.email  xxxxxx@foxmail.com

// @license.name  Apache 2.0
// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html

// @host      localhost
// @schemes http https
// @accept json
// @query.collection.format multi
func main() {
    engine := gin.New()
    engine.Use(gin.Recovery())

    engine.GET("/helloworld", Helloworld)
    engine.POST("/login/email", user_center.NewUserController().LoginOrRegisterWithEmail)

    // swagger stuff
    engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    controller.LoadRouters(engine)

    if err := engine.Run(":9099"); err != nil {
        fmt.Println("ListenAndServe: ", err.Error())
    }
}

src/controller/router.go

package controller

import (
    "github.com/gin-gonic/gin"
    "swag/src/controller/api/user_center"
)

// LoadRouters collection and registration of HandlerRouter
func LoadRouters(engine *gin.Engine) {
    apiV1 := engine.Group("/api/v1")
    {
        user := apiV1.Group("/user")
        {
            userController := user_center.NewUserController()
            user.POST("/login/email", userController.LoginOrRegisterWithEmail)
        }
    }
}

src/controller/api/base_controller.go

package api

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

type RequestSchema interface {
    Validate() error
}

type BaseController struct {
    context *gin.Context
}

func (b *BaseController) Init(c *gin.Context) {
    b.context = c
}

// SuccessResponse write success response and specify http status_code
func (b *BaseController) SuccessResponse(data interface{}, httpCode ...int) {
    statusCode := http.StatusOK
    if len(httpCode) > 0 {
        statusCode = httpCode[0]
    }
    b.context.JSON(statusCode, gin.H{
        "code":    0,
        "message": nil,
        "data":    data,
    })
}

src/controller/api/user_center/user.go

package user_center

import (
    "github.com/gin-gonic/gin"
    "swag/src/controller/api"
)

type userController struct {
    api.BaseController
}

func NewUserController() *userController {
    return &userController{api.BaseController{}}
}

type emailLoginRequest struct {
    Email      string `json:"email"`
    VerifyCode string `json:"verifyCode,omitempty"`
}

// LoginOrRegisterWithEmail godoc
// @Summary      login an account
// @Description  login with email
// @Tags         accounts
// @Accept       json
// @Produce      json
// @Success      200  {object}  dto.UserDTO
// @Router       /user/login/email [get,post]
func (ctl *userController) LoginOrRegisterWithEmail(c *gin.Context) {
    ctl.Init(c)
    var req emailLoginRequest
    err := c.ShouldBindJSON(&req)
    if err != nil {
        ctl.ErrorResponse("xxxx")
        return
    }
    ctl.SuccessResponse(map[string]interface{}{})
    return
}

When I run swag init -d src/cmd -g main.go, it does generate docs directory in swag/docs,

but the paths field in swagger.json or swagger.yaml is empty.

why it doesn't detect the handler LoginOrRegisterWithEmail, which defined in src/controller/api/user_center/user.go ?

tomy128 commented 1 year ago

after my tests, if I define handler in main.go, it will be detected properly. like this:

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    "net/http"
        "swag/src/controller"
)

// Helloworld PingExample godoc
// @Summary ping example
// @Schemes
// @Description do ping
// @Tags example
// @Accept json
// @Produce json
// @Success 200 {string} Helloworld
// @Router /example/helloworld [get]
func Helloworld(g *gin.Context) {
    g.JSON(http.StatusOK, "helloworld")
}

// @title           MetaQ
// @version         1.0
// @description     xxxxxxx

// @contact.name   hahahah
// @contact.email  xxxxxx@foxmail.com

// @license.name  Apache 2.0
// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html

// @host      localhost
// @schemes http https
// @accept json
// @query.collection.format multi
func main() {
    engine := gin.New()
    engine.Use(gin.Recovery())

    engine.GET("/helloworld", Helloworld)
    engine.POST("/login/email", user_center.NewUserController().LoginOrRegisterWithEmail)

    // swagger stuff
    engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    controller.LoadRouters(engine)

    if err := engine.Run(":9099"); err != nil {
        fmt.Println("ListenAndServe: ", err.Error())
    }
}
fdd92 commented 1 year ago

I had the same problem, but I solved it. Maybe you could use swag init -d src/controller -g ../cmd/main.go

tomy128 commented 1 year ago

I had the same problem, but I solved it. Maybe you could use swag init -d src/controller -g ../cmd/main.go

It's do solve it, this should be closed. thks.

I had another problem, maybe you could help help me.

In the LoginOrRegisterWithEmail godoc

// @Success      200  {object}  dto.UserDTO

this will generate a model schema UserDTO,

but what I need (function return) is something different like this: in the code above:

ctl.SuccessResponse(map[string]interface{}{})

the ctl.SuccessResponse will convert the data input to a new format like:

gin.H{
        "business_code":    0,
        "message": nil,
        "data":    data,  // this is the `SuccessResponse` input data
    }

how to make swag generate model schema like this?

tomy128 commented 1 year ago

I had the same problem, but I solved it. Maybe you could use swag init -d src/controller -g ../cmd/main.go

It's do solve it, this should be closed. thks.

I had another problem, maybe you could help help me.

In the LoginOrRegisterWithEmail godoc

// @Success      200  {object}  dto.UserDTO

this will generate a model schema UserDTO,

but what I need (function return) is something different like this: in the code above:

ctl.SuccessResponse(map[string]interface{}{})

the ctl.SuccessResponse will convert the data input to a new format like:

gin.H{
      "business_code":    0,
      "message": nil,
      "data":    data,  // this is the `SuccessResponse` input data
  }

how to make swag generate model schema like this?

Okay, I know how to implement this finally. :-)

use Model composition in response

two things should be aware of:

nyetwurk commented 3 months ago

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

swaggerfiles no longer has Handler in 2.0.0

is there a porting guide?