go-swagger未生成模型信息。

huangapple go评论89阅读模式
英文:

go-swagger not generating model info

问题

这是我的简单 REST 服务:

// Package classification User API.
//
// the purpose of this application is to provide an application
// that is using plain go code to define an API
//
// This should demonstrate all the possible comment annotations
// that are available to turn go code into a fully compliant swagger 2.0 spec
//
// Terms Of Service:
//
// there are no TOS at this moment, use at your own risk we take no responsibility
//
//     Schemes: http, https
//     Host: localhost
//     BasePath: /v2
//     Version: 0.0.1
//     License: MIT http://opensource.org/licenses/MIT
//     Contact: John Doe<john.doe@example.com> http://john.doe.com
//
//     Consumes:
//     - application/json
//     - application/xml
//
//     Produces:
//     - application/json
//     - application/xml
//
//
// swagger:meta
package main

import (
	"github.com/gin-gonic/gin"
	"strconv"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"gopkg.in/gorp.v1"
	"log"
)

// swagger:model
// User represents the user for this application
//
// A user is the security principal for this application.
// It's also used as one of main axis for reporting.
//
// A user can have friends with whom they can share what they like.
//
type User struct {
	// the id for this user
	//
	// required: true
	// min: 1
	Id int64 `db:"id" json:"id"`
	// the first name for this user
	// required: true
	// min length: 3
	Firstname string `db:"firstname" json:"firstname"`
	// the last name for this user
	// required: true
	// min length: 3
	Lastname string `db:"lastname" json:"lastname"`
}

func main() {
	r := gin.Default()
	r.Use(Cors())
	v1 := r.Group("api/v1")
	{
		v1.GET("/users", GetUsers)
		v1.GET("/users/:id", GetUser)
		v1.POST("/users", PostUser)
		v1.PUT("/users/:id", UpdateUser)
		v1.DELETE("/users/:id", DeleteUser)
		v1.OPTIONS("/users", OptionsUser)     // POST
		v1.OPTIONS("/users/:id", OptionsUser) // PUT, DELETE
	}
	r.Run(":8696")
}


func GetUsers(c *gin.Context) {
	// swagger:route GET /user listPets pets users
	//
	// Lists pets filtered by some parameters.
	//
	// This will show all available pets by default.
	// You can get the pets that are out of stock
	//
	//     Consumes:
	//     - application/json
	//     - application/x-protobuf
	//
	//     Produces:
	//     - application/json
	//     - application/x-protobuf
	//
	//     Schemes: http, https, ws, wss
	//
	//     Security:
	//       api_key:
	//       oauth: read, write
	//
	//     Responses:
	//       default: genericError
	//       200: someResponse
	//       422: validationError
	var users []User
	_, err := dbmap.Select(&users, "SELECT * FROM user")
	if err == nil {
		c.JSON(200, users)
	} else {
		c.JSON(404, gin.H{"error": "no user(s) into the table"})
	}
	// curl -i http://localhost:8080/api/v1/users
}

func GetUser(c *gin.Context) {
	id := c.Params.ByName("id")
	var user User
	err := dbmap.SelectOne(&user, "SELECT * FROM user WHERE id=?", id)
	if err == nil {
		user_id, _ := strconv.ParseInt(id, 0, 64)
		content := &User{
			Id:        user_id,
			Firstname: user.Firstname,
			Lastname:  user.Lastname,
		}
		c.JSON(200, content)
	} else {
		c.JSON(404, gin.H{"error": "user not found"})
	}
	// curl -i http://localhost:8080/api/v1/users/1
}

func PostUser(c *gin.Context) {
	var user User
	c.Bind(&user)
	if user.Firstname != "" && user.Lastname != "" {
		if insert, _ := dbmap.Exec(`INSERT INTO user (firstname, lastname) VALUES (?, ?)`, user.Firstname, user.Lastname); insert != nil {
			user_id, err := insert.LastInsertId()
			if err == nil {
				content := &User{
					Id:        user_id,
					Firstname: user.Firstname,
					Lastname:  user.Lastname,
				}
				c.JSON(201, content)
			} else {
				checkErr(err, "Insert failed")
			}
		}
	} else {
		c.JSON(422, gin.H{"error": "fields are empty"})
	}
	// curl -i -X POST -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Queen\" }" http://localhost:8080/api/v1/users
}

func UpdateUser(c *gin.Context) {
	id := c.Params.ByName("id")
	var user User
	err := dbmap.SelectOne(&user, "SELECT * FROM user WHERE id=?", id)
	if err == nil {
		var json User
		c.Bind(&json)
		user_id, _ := strconv.ParseInt(id, 0, 64)
		user := User{
			Id:        user_id,
			Firstname: json.Firstname,
			Lastname:  json.Lastname,
		}
		if user.Firstname != "" && user.Lastname != "" {
			_, err = dbmap.Update(&user)
			if err == nil {
				c.JSON(200, user)
			} else {
				checkErr(err, "Updated failed")
			}
		} else {
			c.JSON(422, gin.H{"error": "fields are empty"})
		}
	} else {
		c.JSON(404, gin.H{"error": "user not found"})
	}
	// curl -i -X PUT -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Merlyn\" }" http://localhost:8080/api/v1/users/1
}

func DeleteUser(c *gin.Context) {
	id := c.Params.ByName("id")
	var user User
	err := dbmap.SelectOne(&user, "SELECT id FROM user WHERE id=?", id)
	if err == nil {
		_, err = dbmap.Delete(&user)
		if err == nil {
			c.JSON(200, gin.H{"id #" + id: " deleted"})
		} else {
			checkErr(err, "Delete failed")
		}
	} else {
		c.JSON(404, gin.H{"error": "user not found"})
	}
	// curl -i -X DELETE http://localhost:8080/api/v1/users/1
}

var dbmap = initDb()
func initDb() *gorp.DbMap {
	db, err := sql.Open("mysql",
		"root:max_123@tcp(127.0.0.1:3306)/gotest")
	checkErr(err, "sql.Open failed")
	dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
	dbmap.AddTableWithName(User{}, "User").SetKeys(true, "Id")
	err = dbmap.CreateTablesIfNotExists()
	checkErr(err, "Create table failed")
	return dbmap
}

func checkErr(err error, msg string) {
	if err != nil {
		log.Fatalln(msg, err)
	}
}


func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
		c.Next()
	}
}

func OptionsUser(c *gin.Context) {
	c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
	c.Writer.Header().Set("Access-Control-Allow-Methods", "DELETE,POST, PUT")
	c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")
	c.Next()
}

现在当我执行以下命令时:
swagger generate spec -o ./swagger.json
生成 JSON 规范时,我得到的结果是:

{
	"consumes": ["application/json", "application/xml"],
	"produces": ["application/json", "application/xml"],
	"schemes": ["http", "https"],
	"swagger": "2.0",
	"info": {
		"description": "the purpose of this application is to provide an application\nthat is using plain go code to define an API\n\nThis should demonstrate all the possible comment annotations\nthat are available to turn go code into a fully compliant swagger 2.0 spec",
		"title": "User API.",
		"termsOfService": "there are no TOS at this moment, use at your own risk we take no responsibility",
		"contact": {
			"name": "John Doe",
			"url": "http://john.doe.com",
			"email": "john.doe@example.com"
		},
		"license": {
			"name": "MIT",
			"url": "http://opensource.org/licenses/MIT"
		},
		"version": "0.0.1"
	},
	"host": "localhost",
	"basePath": "/v2",
	"paths": {
		"/user": {
			"get": {
				"description": "This will show all available pets by default.\nYou can get the pets that are out of stock",
				"consumes": ["application/json", "application/x-protobuf"],
				"produces": ["application/json", "application/x-protobuf"],
				"schemes": ["http", "https", "ws", "wss"],
				"tags": ["listPets", "pets"],
				"summary": "Lists pets filtered by some parameters.",
				"operationId": "users",
				"security": [{
					"api_key": null
				}, {
					"oauth": ["read", "write"]
				}],
				"responses": {
					"200": {
						"$ref": "#/responses/someResponse"
					},
					"422": {
						"$ref": "#/responses/validationError"
					},
					"default": {
						"$ref": "#/responses/genericError"
					}
				}
			}
		}
	},
	"definitions": {}
}

请注意,我的定义部分是空的,不确定为什么。
如果我将相同的 JSON 规范粘贴到 http://editor.swagger.io/#/ 中,
它会显示错误:

Error
Object
message:  "options.definition is required"
code:  "UNCAUGHT_SWAY_WORKER_ERROR"

有关生成 Swagger 文档的正确方法的任何指导都会有所帮助。

英文:

Here is my simple rest service:

// Package classification User API.
//
// the purpose of this application is to provide an application
// that is using plain go code to define an API
//
// This should demonstrate all the possible comment annotations
// that are available to turn go code into a fully compliant swagger 2.0 spec
//
// Terms Of Service:
//
// there are no TOS at this moment, use at your own risk we take no responsibility
//
//     Schemes: http, https
//     Host: localhost
//     BasePath: /v2
//     Version: 0.0.1
//     License: MIT http://opensource.org/licenses/MIT
//     Contact: John Doe<john.doe@example.com> http://john.doe.com
//
//     Consumes:
//     - application/json
//     - application/xml
//
//     Produces:
//     - application/json
//     - application/xml
//
//
// swagger:meta
package main
import (
"github.com/gin-gonic/gin"
"strconv"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"gopkg.in/gorp.v1"
"log"
)
// swagger:model
// User represents the user for this application
//
// A user is the security principal for this application.
// It's also used as one of main axis for reporting.
//
// A user can have friends with whom they can share what they like.
//
type User struct {
// the id for this user
//
// required: true
// min: 1
Id int64 `db:"id" json:"id"`
// the first name for this user
// required: true
// min length: 3
Firstname string `db:"firstname" json:"firstname"`
// the last name for this user
// required: true
// min length: 3
Lastname string `db:"lastname" json:"lastname"`
}
func main() {
r := gin.Default()
r.Use(Cors())
v1 := r.Group("api/v1")
{
v1.GET("/users", GetUsers)
v1.GET("/users/:id", GetUser)
v1.POST("/users", PostUser)
v1.PUT("/users/:id", UpdateUser)
v1.DELETE("/users/:id", DeleteUser)
v1.OPTIONS("/users", OptionsUser)     // POST
v1.OPTIONS("/users/:id", OptionsUser) // PUT, DELETE
}
r.Run(":8696")
}
func GetUsers(c *gin.Context) {
// swagger:route GET /user listPets pets users
//
// Lists pets filtered by some parameters.
//
// This will show all available pets by default.
// You can get the pets that are out of stock
//
//     Consumes:
//     - application/json
//     - application/x-protobuf
//
//     Produces:
//     - application/json
//     - application/x-protobuf
//
//     Schemes: http, https, ws, wss
//
//     Security:
//       api_key:
//       oauth: read, write
//
//     Responses:
//       default: genericError
//       200: someResponse
//       422: validationError
var users []User
_, err := dbmap.Select(&users, "SELECT * FROM user")
if err == nil {
c.JSON(200, users)
} else {
c.JSON(404, gin.H{"error": "no user(s) into the table"})
}
// curl -i http://localhost:8080/api/v1/users
}
func GetUser(c *gin.Context) {
id := c.Params.ByName("id")
var user User
err := dbmap.SelectOne(&user, "SELECT * FROM user WHERE id=?", id)
if err == nil {
user_id, _ := strconv.ParseInt(id, 0, 64)
content := &User{
Id: user_id,
Firstname: user.Firstname,
Lastname: user.Lastname,
}
c.JSON(200, content)
} else {
c.JSON(404, gin.H{"error": "user not found"})
}
// curl -i http://localhost:8080/api/v1/users/1
}
func PostUser(c *gin.Context) {
var user User
c.Bind(&user)
if user.Firstname != "" && user.Lastname != "" {
if insert, _ := dbmap.Exec(`INSERT INTO user (firstname, lastname) VALUES (?, ?)`, user.Firstname, user.Lastname); insert != nil {
user_id, err := insert.LastInsertId()
if err == nil {
content := &User{
Id: user_id,
Firstname: user.Firstname,
Lastname: user.Lastname,
}
c.JSON(201, content)
} else {
checkErr(err, "Insert failed")
}
}
} else {
c.JSON(422, gin.H{"error": "fields are empty"})
}
// curl -i -X POST -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Queen\" }" http://localhost:8080/api/v1/users
}
func UpdateUser(c *gin.Context) {
id := c.Params.ByName("id")
var user User
err := dbmap.SelectOne(&user, "SELECT * FROM user WHERE id=?", id)
if err == nil {
var json User
c.Bind(&json)
user_id, _ := strconv.ParseInt(id, 0, 64)
user := User{
Id: user_id,
Firstname: json.Firstname,
Lastname: json.Lastname,
}
if user.Firstname != "" && user.Lastname != ""{
_, err = dbmap.Update(&user)
if err == nil {
c.JSON(200, user)
} else {
checkErr(err, "Updated failed")
}
} else {
c.JSON(422, gin.H{"error": "fields are empty"})
}
} else {
c.JSON(404, gin.H{"error": "user not found"})
}
// curl -i -X PUT -H "Content-Type: application/json" -d "{ \"firstname\": \"Thea\", \"lastname\": \"Merlyn\" }" http://localhost:8080/api/v1/users/1
}
func DeleteUser(c *gin.Context) {
id := c.Params.ByName("id")
var user User
err := dbmap.SelectOne(&user, "SELECT id FROM user WHERE id=?", id)
if err == nil {
_, err = dbmap.Delete(&user)
if err == nil {
c.JSON(200, gin.H{"id #" + id: " deleted"})
} else {
checkErr(err, "Delete failed")
}
} else {
c.JSON(404, gin.H{"error": "user not found"})
}
// curl -i -X DELETE http://localhost:8080/api/v1/users/1
}
var dbmap = initDb()
func initDb() *gorp.DbMap {
db, err := sql.Open("mysql",
"root:max_123@tcp(127.0.0.1:3306)/gotest")
checkErr(err, "sql.Open failed")
dbmap := &gorp.DbMap{Db: db, Dialect:           gorp.MySQLDialect{"InnoDB", "UTF8"}}
dbmap.AddTableWithName(User{}, "User").SetKeys(true, "Id")
err = dbmap.CreateTablesIfNotExists()
checkErr(err, "Create table failed")
return dbmap
}
func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err)
}
}
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
c.Next()
}
}
func OptionsUser(c *gin.Context) {
c.Writer.Header().Add("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Methods", "DELETE,POST, PUT")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")
c.Next()
}

Now when I'm executing :
swagger generate spec -o ./swagger.json
to generate the json spec I'm getting:

{
"consumes": ["application/json", "application/xml"],
"produces": ["application/json", "application/xml"],
"schemes": ["http", "https"],
"swagger": "2.0",
"info": {
"description": "the purpose of this application is to provide an application\nthat is using plain go code to define an API\n\nThis should demonstrate all the possible comment annotations\nthat are available to turn go code into a fully compliant swagger 2.0 spec",
"title": "User API.",
"termsOfService": "there are no TOS at this moment, use at your own risk we take no responsibility",
"contact": {
"name": "John Doe",
"url": "http://john.doe.com",
"email": "john.doe@example.com"
},
"license": {
"name": "MIT",
"url": "http://opensource.org/licenses/MIT"
},
"version": "0.0.1"
},
"host": "localhost",
"basePath": "/v2",
"paths": {
"/user": {
"get": {
"description": "This will show all available pets by default.\nYou can get the pets that are out of stock",
"consumes": ["application/json", "application/x-protobuf"],
"produces": ["application/json", "application/x-protobuf"],
"schemes": ["http", "https", "ws", "wss"],
"tags": ["listPets", "pets"],
"summary": "Lists pets filtered by some parameters.",
"operationId": "users",
"security": [{
"api_key": null
}, {
"oauth": ["read", "write"]
}],
"responses": {
"200": {
"$ref": "#/responses/someResponse"
},
"422": {
"$ref": "#/responses/validationError"
},
"default": {
"$ref": "#/responses/genericError"
}
}
}
}
},
"definitions": {}
}

Note that my definitions are empty, not sure why.
If I paste the same json spec in http://editor.swagger.io/#/
It says

Error
Object
message:  "options.definition is required"
code:  "UNCAUGHT_SWAY_WORKER_ERROR"

Any directions on what is the right way to generate swagger documentation would help

答案1

得分: 2

这是因为go-swagger无法检测到您定义的使用情况。我假设您总是会有一个描述参数的结构体,并且这些参数会始终使用当前正在使用的定义。
如果您能将这个问题作为一个问题提交到存储库中,并附上您的示例程序,那将非常好。我会将其添加到我的测试中。

英文:

It's because go-swagger can't detect the usage of your definitions. I made the assumption that you'd always have a struct describing the parameters and that those would always use the definitions that are in use.
It would be great if you could submit this question as an issue on the repo with your sample program. I'll add it to my tests.

huangapple
  • 本文由 发表于 2016年2月26日 23:44:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/35655966.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定