diff --git a/README.md b/README.md index e5fd8c6..139bc9e 100644 --- a/README.md +++ b/README.md @@ -3,93 +3,103 @@ ### 1. 编译goctl-swagger插件 ``` -$ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromicro/goctl-swagger +GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/fachebot/goctl-swagger ``` ### 2. 配置环境 + 将$GOPATH/bin中的goctl-swagger添加到环境变量 ### 3. 使用姿势 * 创建api文件 + ```go info( - title: "type title here" - desc: "type desc here" - author: "type author here" - email: "type email here" - version: "type version here" + title: "type title here" + desc: "type desc here" + author: "type author here" + email: "type email here" + version: "type version here" ) type ( - RegisterReq { - Username string `json:"username"` - Password string `json:"password"` - Mobile string `json:"mobile"` - } - - LoginReq { - Username string `json:"username"` - Password string `json:"password"` - } - - UserInfoReq { - Id string `path:"id"` - } - - UserInfoReply { - Name string `json:"name"` - Age int `json:"age"` - Birthday string `json:"birthday"` - Description string `json:"description"` - Tag []string `json:"tag"` - } - - UserSearchReq { - KeyWord string `form:"keyWord"` - } + RegisterReq { + Username string `json:"username"` + Password string `json:"password"` + Mobile string `json:"mobile"` + } + + LoginReq { + Username string `json:"username"` + Password string `json:"password"` + } + + UserInfoReq { + Id string `path:"id"` + } + + UserInfoReply { + Name string `json:"name"` + Age int `json:"age"` + Birthday string `json:"birthday"` + Description string `json:"description"` + Tag []string `json:"tag"` + } + + UserSearchReq { + KeyWord string `form:"keyWord"` + } ) service user-api { - @doc( - summary: "注册" - ) - @handler register - post /api/user/register (RegisterReq) - - @doc( - summary: "登录" - ) - @handler login - post /api/user/login (LoginReq) - - @doc( - summary: "获取用户信息" - ) - @handler getUserInfo - get /api/user/:id (UserInfoReq) returns (UserInfoReply) - - @doc( - summary: "用户搜索" - ) - @handler searchUser - get /api/user/search (UserSearchReq) returns (UserInfoReply) + @doc( + summary: "注册" + ) + @handler register + post /api/user/register (RegisterReq) + + @doc( + summary: "登录" + ) + @handler login + post /api/user/login (LoginReq) + + @doc( + summary: "获取用户信息" + ) + @handler getUserInfo + get /api/user/:id (UserInfoReq) returns (UserInfoReply) + + @doc( + summary: "用户搜索" + ) + @handler searchUser + get /api/user/search (UserSearchReq) returns (UserInfoReply) } ``` + * 生成swagger.json 文件 + ```shell script - $ goctl api plugin -plugin goctl-swagger="swagger -filename user.json" -api user.api -dir . + goctl api plugin -plugin goctl-swagger="swagger -filename user.json" -api user.api -dir . ``` + * 指定Host,basePath [api-host-and-base-path](https://swagger.io/docs/specification/2-0/api-host-and-base-path/) + ```shell script - $ goctl api plugin -plugin goctl-swagger="swagger -filename user.json -host 127.0.0.2 -basepath /api" -api user.api -dir . + goctl api plugin -plugin goctl-swagger="swagger -filename user.json -host 127.0.0.2 -basepath /api" -api user.api -dir . ``` + * swagger ui 查看生成的文档 + ```shell script - $ docker run --rm -p 8083:8080 -e SWAGGER_JSON=/foo/user.json -v $PWD:/foo swaggerapi/swagger-ui + docker run --rm -p 8083:8080 -e SWAGGER_JSON=/foo/user.json -v $PWD:/foo swaggerapi/swagger-ui ``` + * Swagger Codegen 生成客户端调用代码(go,javascript,php) + ```shell script for l in go javascript php; do docker run --rm -v "$(pwd):/go-work" swaggerapi/swagger-codegen-cli generate \ @@ -97,4 +107,4 @@ $ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromic -l "$l" \ -o "/go-work/clients/$l" done - ``` \ No newline at end of file + ``` diff --git a/action/action.go b/action/action.go index ae6459c..4a4120c 100644 --- a/action/action.go +++ b/action/action.go @@ -1,9 +1,9 @@ package action import ( + "github.com/fachebot/goctl-swagger/generate" "github.com/urfave/cli/v2" "github.com/zeromicro/go-zero/tools/goctl/plugin" - "github.com/zeromicro/goctl-swagger/generate" ) func Generator(ctx *cli.Context) error { diff --git a/generate/entities.go b/generate/entities.go index ec55c02..729282f 100644 --- a/generate/entities.go +++ b/generate/entities.go @@ -124,7 +124,7 @@ type swaggerOperationObject struct { OperationID string `json:"operationId"` Responses swaggerResponsesObject `json:"responses"` Parameters swaggerParametersObject `json:"parameters,omitempty"` - RequestBody struct { + RequestBody *struct { Content swaggerContentObject `json:"content,omitempty"` } `json:"requestBody,omitempty"` Tags []string `json:"tags,omitempty"` diff --git a/generate/parser.go b/generate/parser.go index a82e357..e6788e5 100644 --- a/generate/parser.go +++ b/generate/parser.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "reflect" + "regexp" "strconv" "strings" "unsafe" @@ -19,12 +20,36 @@ const ( defaultOption = "default" stringOption = "string" optionalOption = "optional" + omitemptyOption = "omitempty" optionsOption = "options" rangeOption = "range" optionSeparator = "|" equalToken = "=" ) +func parseRangeOption(option string) (float64, float64, bool) { + const str = "\\[([+-]?\\d+(\\.\\d+)?):([+-]?\\d+(\\.\\d+)?)\\]" + result := regexp.MustCompile(str).FindStringSubmatch(option) + if len(result) != 5 { + return 0, 0, false + } + + min, err := strconv.ParseFloat(result[1], 64) + if err != nil { + return 0, 0, false + } + + max, err := strconv.ParseFloat(result[3], 64) + if err != nil { + return 0, 0, false + } + + if max < min { + return min, min, true + } + return min, max, true +} + func applyGenerate(p *plugin.Plugin, host string, basePath string) (*swaggerObject, error) { title, _ := strconv.Unquote(p.Api.Info.Properties["title"]) version, _ := strconv.Unquote(p.Api.Info.Properties["version"]) @@ -136,16 +161,37 @@ func renderServiceRoutes(service spec.Service, groups []spec.Group, paths swagge sp.Required = true continue } + + required := true for _, option := range tag.Options { + if strings.HasPrefix(option, optionsOption) { + segs := strings.SplitN(option, equalToken, 2) + if len(segs) == 2 { + sp.Enum = strings.Split(segs[1], optionSeparator) + } + } + + if strings.HasPrefix(option, rangeOption) { + segs := strings.SplitN(option, equalToken, 2) + if len(segs) == 2 { + min, max, ok := parseRangeOption(segs[1]) + if ok { + sp.Schema.Minimum = min + sp.Schema.Maximum = max + } + } + } + if strings.HasPrefix(option, defaultOption) { segs := strings.Split(option, equalToken) if len(segs) == 2 { sp.Default = segs[1] } - } else if !strings.HasPrefix(option, optionalOption) { - sp.Required = true + } else if strings.HasPrefix(option, optionalOption) || strings.HasPrefix(option, omitemptyOption) { + required = false } } + sp.Required = required } if len(member.Comment) > 0 { @@ -288,16 +334,20 @@ func renderReplyAsDefinition(d swaggerDefinitionsObject, m messageMap, p []spec. } continue } + + required := true for _, option := range tag.Options { - switch { - case !strings.HasPrefix(option, optionalOption): - if !contains(schema.Required, tag.Name) { - schema.Required = append(schema.Required, tag.Name) - } - // case strings.HasPrefix(option, defaultOption): - // case strings.HasPrefix(option, optionsOption): + // case strings.HasPrefix(option, defaultOption): + // case strings.HasPrefix(option, optionsOption): + + if strings.HasPrefix(option, optionalOption) || strings.HasPrefix(option, omitemptyOption) { + required = false } } + + if required && !contains(schema.Required, tag.Name) { + schema.Required = append(schema.Required, tag.Name) + } } } @@ -409,7 +459,19 @@ func schemaOfField(member spec.Member) swaggerSchemaObject { ret.Default = segs[1] } case strings.HasPrefix(option, optionsOption): - + segs := strings.SplitN(option, equalToken, 2) + if len(segs) == 2 { + ret.Enum = strings.Split(segs[1], optionSeparator) + } + case strings.HasPrefix(option, rangeOption): + segs := strings.SplitN(option, equalToken, 2) + if len(segs) == 2 { + min, max, ok := parseRangeOption(segs[1]) + if ok { + ret.Minimum = min + ret.Maximum = max + } + } } } } diff --git a/go.mod b/go.mod index 7f736a3..6df53cb 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/zeromicro/goctl-swagger +module github.com/fachebot/goctl-swagger go 1.16 diff --git a/main.go b/main.go index df88b6d..098a758 100644 --- a/main.go +++ b/main.go @@ -5,8 +5,8 @@ import ( "os" "runtime" + "github.com/fachebot/goctl-swagger/action" "github.com/urfave/cli/v2" - "github.com/zeromicro/goctl-swagger/action" ) var (