Merge pull request #30 from fachebot/main
添加options、range和omitempty选项的支持
This commit is contained in:
		
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							@@ -3,15 +3,17 @@
 | 
				
			|||||||
### 1. 编译goctl-swagger插件
 | 
					### 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. 配置环境
 | 
					### 2. 配置环境
 | 
				
			||||||
 | 
					
 | 
				
			||||||
将$GOPATH/bin中的goctl-swagger添加到环境变量
 | 
					将$GOPATH/bin中的goctl-swagger添加到环境变量
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 3. 使用姿势
 | 
					### 3. 使用姿势
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* 创建api文件
 | 
					* 创建api文件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```go
 | 
					    ```go
 | 
				
			||||||
    info(
 | 
					    info(
 | 
				
			||||||
     title: "type title here"
 | 
					     title: "type title here"
 | 
				
			||||||
@@ -77,19 +79,27 @@ $ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/zeromic
 | 
				
			|||||||
     get /api/user/search (UserSearchReq) returns (UserInfoReply)
 | 
					     get /api/user/search (UserSearchReq) returns (UserInfoReply)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ```
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* 生成swagger.json 文件
 | 
					* 生成swagger.json 文件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```shell script
 | 
					    ```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/)
 | 
					* 指定Host,basePath [api-host-and-base-path](https://swagger.io/docs/specification/2-0/api-host-and-base-path/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```shell script
 | 
					    ```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 查看生成的文档
 | 
					* swagger ui 查看生成的文档
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```shell script
 | 
					    ```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)
 | 
					* Swagger Codegen 生成客户端调用代码(go,javascript,php)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ```shell script
 | 
					  ```shell script
 | 
				
			||||||
  for l in go javascript php; do
 | 
					  for l in go javascript php; do
 | 
				
			||||||
    docker run --rm -v "$(pwd):/go-work" swaggerapi/swagger-codegen-cli generate \
 | 
					    docker run --rm -v "$(pwd):/go-work" swaggerapi/swagger-codegen-cli generate \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package action
 | 
					package action
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/fachebot/goctl-swagger/generate"
 | 
				
			||||||
	"github.com/urfave/cli/v2"
 | 
						"github.com/urfave/cli/v2"
 | 
				
			||||||
	"github.com/zeromicro/go-zero/tools/goctl/plugin"
 | 
						"github.com/zeromicro/go-zero/tools/goctl/plugin"
 | 
				
			||||||
	"github.com/zeromicro/goctl-swagger/generate"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Generator(ctx *cli.Context) error {
 | 
					func Generator(ctx *cli.Context) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,7 +124,7 @@ type swaggerOperationObject struct {
 | 
				
			|||||||
	OperationID string                  `json:"operationId"`
 | 
						OperationID string                  `json:"operationId"`
 | 
				
			||||||
	Responses   swaggerResponsesObject  `json:"responses"`
 | 
						Responses   swaggerResponsesObject  `json:"responses"`
 | 
				
			||||||
	Parameters  swaggerParametersObject `json:"parameters,omitempty"`
 | 
						Parameters  swaggerParametersObject `json:"parameters,omitempty"`
 | 
				
			||||||
	RequestBody struct {
 | 
						RequestBody *struct {
 | 
				
			||||||
		Content swaggerContentObject `json:"content,omitempty"`
 | 
							Content swaggerContentObject `json:"content,omitempty"`
 | 
				
			||||||
	} `json:"requestBody,omitempty"`
 | 
						} `json:"requestBody,omitempty"`
 | 
				
			||||||
	Tags       []string `json:"tags,omitempty"`
 | 
						Tags       []string `json:"tags,omitempty"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"unsafe"
 | 
						"unsafe"
 | 
				
			||||||
@@ -19,12 +20,36 @@ const (
 | 
				
			|||||||
	defaultOption   = "default"
 | 
						defaultOption   = "default"
 | 
				
			||||||
	stringOption    = "string"
 | 
						stringOption    = "string"
 | 
				
			||||||
	optionalOption  = "optional"
 | 
						optionalOption  = "optional"
 | 
				
			||||||
 | 
						omitemptyOption = "omitempty"
 | 
				
			||||||
	optionsOption   = "options"
 | 
						optionsOption   = "options"
 | 
				
			||||||
	rangeOption     = "range"
 | 
						rangeOption     = "range"
 | 
				
			||||||
	optionSeparator = "|"
 | 
						optionSeparator = "|"
 | 
				
			||||||
	equalToken      = "="
 | 
						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) {
 | 
					func applyGenerate(p *plugin.Plugin, host string, basePath string) (*swaggerObject, error) {
 | 
				
			||||||
	title, _ := strconv.Unquote(p.Api.Info.Properties["title"])
 | 
						title, _ := strconv.Unquote(p.Api.Info.Properties["title"])
 | 
				
			||||||
	version, _ := strconv.Unquote(p.Api.Info.Properties["version"])
 | 
						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
 | 
													sp.Required = true
 | 
				
			||||||
								continue
 | 
													continue
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												required := true
 | 
				
			||||||
							for _, option := range tag.Options {
 | 
												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) {
 | 
													if strings.HasPrefix(option, defaultOption) {
 | 
				
			||||||
									segs := strings.Split(option, equalToken)
 | 
														segs := strings.Split(option, equalToken)
 | 
				
			||||||
									if len(segs) == 2 {
 | 
														if len(segs) == 2 {
 | 
				
			||||||
										sp.Default = segs[1]
 | 
															sp.Default = segs[1]
 | 
				
			||||||
									}
 | 
														}
 | 
				
			||||||
								} else if !strings.HasPrefix(option, optionalOption) {
 | 
													} else if strings.HasPrefix(option, optionalOption) || strings.HasPrefix(option, omitemptyOption) {
 | 
				
			||||||
									sp.Required = true
 | 
														required = false
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
												sp.Required = required
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if len(member.Comment) > 0 {
 | 
											if len(member.Comment) > 0 {
 | 
				
			||||||
@@ -288,16 +334,20 @@ func renderReplyAsDefinition(d swaggerDefinitionsObject, m messageMap, p []spec.
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									required := true
 | 
				
			||||||
				for _, option := range tag.Options {
 | 
									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, defaultOption):
 | 
				
			||||||
					// case strings.HasPrefix(option, optionsOption):
 | 
										// 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]
 | 
										ret.Default = segs[1]
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case strings.HasPrefix(option, optionsOption):
 | 
								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
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
				
			|||||||
module github.com/zeromicro/goctl-swagger
 | 
					module github.com/fachebot/goctl-swagger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go 1.16
 | 
					go 1.16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user