Swagger update

This commit is contained in:
zodial
2024-10-18 14:36:13 +08:00
parent 744362acaa
commit d77a93f2f6
2 changed files with 52 additions and 16 deletions
+41 -14
View File
@@ -44,6 +44,11 @@ func (SwaggerCommand) Configure() command.Configure {
Description: "指定文档语言,如说明的下一行是‘// @lang:en name’则‘name’代替原说明", Description: "指定文档语言,如说明的下一行是‘// @lang:en name’则‘name’代替原说明",
Default: "", Default: "",
}, },
{
Name: "host",
Description: "指定接口Host",
Default: "",
},
}, },
}, },
} }
@@ -55,6 +60,7 @@ func (SwaggerCommand) Execute(input command.Input) {
out := input.GetOption("out") out := input.GetOption("out")
path := input.GetOption("path") path := input.GetOption("path")
language = input.GetOption("lang") language = input.GetOption("lang")
host := input.GetOption("host")
swagger := openapi.Spec{ swagger := openapi.Spec{
Swagger: "2.0", Swagger: "2.0",
@@ -70,6 +76,16 @@ func (SwaggerCommand) Execute(input command.Input) {
Extensions: nil, Extensions: nil,
GlobalOptions: nil, GlobalOptions: nil,
} }
if host != "" {
re := regexp.MustCompile(`^(https?)://(.+)`)
matches := re.FindStringSubmatch(host)
if matches != nil {
swagger.Schemes = []string{matches[1]}
swagger.Host = matches[2]
} else {
swagger.Host = host
}
}
if parser.DirIsExist(source) { if parser.DirIsExist(source) {
data, _ := os.ReadFile(source) data, _ := os.ReadFile(source)
json.Unmarshal(data, &swagger) json.Unmarshal(data, &swagger)
@@ -77,14 +93,14 @@ func (SwaggerCommand) Execute(input command.Input) {
allProtoc := parser.NewProtocParserForDir(path) allProtoc := parser.NewProtocParserForDir(path)
for s, parsers := range allProtoc { for s, parsers := range allProtoc {
prefix := getPrefix(path, s) pkg := getPackage(path, s)
for _, fileParser := range parsers { for _, fileParser := range parsers {
for _, message := range fileParser.Messages { for _, message := range fileParser.Messages {
name, parameter := messageToSchemas(prefix, message, &swagger) name, parameter := messageToSchemas(pkg, message, &swagger)
swagger.Definitions[defName(name)] = parameter swagger.Definitions[defName(name)] = parameter
} }
for _, enum := range fileParser.Enums { for _, enum := range fileParser.Enums {
name, parameter := enumToMessage(prefix, enum) name, parameter := enumToMessage(pkg, enum)
swagger.Definitions[defName(name)] = parameter swagger.Definitions[defName(name)] = parameter
} }
@@ -92,11 +108,22 @@ func (SwaggerCommand) Execute(input command.Input) {
} }
// 全局定义后在生成url // 全局定义后在生成url
for s, parsers := range allProtoc { for s, parsers := range allProtoc {
prefix := getPrefix(path, s) pkg := getPackage(path, s)
for _, fileParser := range parsers { for _, fileParser := range parsers {
for _, service := range fileParser.Services { for _, service := range fileParser.Services {
var prefix string
if routeGroup, ok := service.Opt["http.RouteGroup"]; ok {
prefix = "/$[" + routeGroup.Val + "]"
if routeGroup.Doc != "" {
re := regexp.MustCompile(`(?i)@prefix=(\w+)`)
match := re.FindStringSubmatch(routeGroup.Doc)
if match != nil {
prefix = "/" + match[1]
}
}
}
for _, rpc := range service.Rpc { for _, rpc := range service.Rpc {
rpcToPath(prefix, rpc, &swagger, parsers, allProtoc, service.Opt) rpcToPath(pkg, rpc, &swagger, parsers, allProtoc, prefix)
} }
} }
} }
@@ -180,7 +207,7 @@ func isValidHTTPStatusCode(code int) bool {
return code >= 100 && code <= 599 return code >= 100 && code <= 599
} }
func rpcToPath(pge string, service parser.ServiceRpc, swagger *openapi.Spec, nowDirProtoc []parser.ProtocFileParser, allProtoc map[string][]parser.ProtocFileParser, serviceOpt map[string]parser.Option) { func rpcToPath(pge string, service parser.ServiceRpc, swagger *openapi.Spec, nowDirProtoc []parser.ProtocFileParser, allProtoc map[string][]parser.ProtocFileParser, prefix string) {
service.Doc = filterLanguage(service.Doc) service.Doc = filterLanguage(service.Doc)
for _, options := range service.Opt { for _, options := range service.Opt {
for _, option := range options { for _, option := range options {
@@ -188,8 +215,8 @@ func rpcToPath(pge string, service parser.ServiceRpc, swagger *openapi.Spec, now
if urlPath == "" { if urlPath == "" {
urlPath = getUrl(service.Opt) urlPath = getUrl(service.Opt)
} }
if routeGroup, ok := serviceOpt["http.RouteGroup"]; ok { if prefix != "" {
urlPath = "$[" + routeGroup.Val + "]" + urlPath urlPath = prefix + urlPath
} }
var path = &openapi.Path{} var path = &openapi.Path{}
if o, ok := swagger.Paths[urlPath]; ok { if o, ok := swagger.Paths[urlPath]; ok {
@@ -562,7 +589,7 @@ func getProtoToSwagger(t string) string {
return "object" return "object"
} }
func getPrefix(path, s string) string { func getPackage(path, s string) string {
got := strings.ReplaceAll(s, path, "") got := strings.ReplaceAll(s, path, "")
got = strings.Trim(got, "/") got = strings.Trim(got, "/")
got = strings.ReplaceAll(got, "/", ".") got = strings.ReplaceAll(got, "/", ".")
@@ -635,12 +662,12 @@ func filterRequired(doc string) (string, bool) {
return strings.Join(newArr, "\n"), isRequired return strings.Join(newArr, "\n"), isRequired
} }
// 仅支持string和number兼容两种写法 @example:xxx xxx 或 @example(xxx xxx) // 仅支持string和number兼容两种写法 @example=xxx 或 @example(xxx xxx)
func filterExample(doc string, ty string) (string, interface{}) { func filterExample(doc string, ty string) (string, interface{}) {
arr := strings.Split(doc, "\n") arr := strings.Split(doc, "\n")
var newArr []string var newArr []string
var example string var example string
re := regexp.MustCompile(`(?i)\s*//\s*@example=(.*)`) re := regexp.MustCompile(`(?i)\s*//\s*@example=(.*|\("*[^)]+"*)`)
re2 := regexp.MustCompile(`(?i)[/\s]*@example\((.*)\)\s*`) re2 := regexp.MustCompile(`(?i)[/\s]*@example\((.*)\)\s*`)
for _, s := range arr { for _, s := range arr {
matches := re.FindStringSubmatch(s) matches := re.FindStringSubmatch(s)
@@ -671,7 +698,7 @@ func filterExample(doc string, ty string) (string, interface{}) {
return strings.Join(newArr, "\n"), result return strings.Join(newArr, "\n"), result
} }
// 首行为默认说明,次行如://@lang:zh xxx 中的 xxx 将替换默认说明 // 首行为默认说明,次行如://@lang=zh xxx 中的 xxx 将替换默认说明
func filterLanguage(doc string) string { func filterLanguage(doc string) string {
arr := strings.Split(doc, "\n") arr := strings.Split(doc, "\n")
if len(arr) < 2 { if len(arr) < 2 {
@@ -721,8 +748,8 @@ func parseTag(str string) string {
return strings.Join(newArr, " \n") return strings.Join(newArr, " \n")
} }
// 例:@query=id @lang=zh @format:string @example=abc 用户ID // 例:@query=id @lang=zh @format=string @example=abc 用户ID
// format默认为int,如format是对象或枚举,即使本地引用,也必须要加上包名,如@format:api.UserStatus // format默认为int,如format是对象或枚举,即使本地引用,也必须要加上包名,如@format=api.UserStatus
func parseParamInPath(option parser.Option) (params openapi.Parameters) { func parseParamInPath(option parser.Option) (params openapi.Parameters) {
re := regexp.MustCompile(`:([a-zA-Z_][a-zA-Z0-9_]*)`) re := regexp.MustCompile(`:([a-zA-Z_][a-zA-Z0-9_]*)`)
matches := re.FindAllStringSubmatch(option.Val, -1) matches := re.FindAllStringSubmatch(option.Val, -1)
+11 -2
View File
@@ -3,7 +3,16 @@
### 2024-10-16 更新 ### 2024-10-16 更新
1. post的payload统一改为application/json 1. post的payload统一改为application/json
2. 支持多语言,新增执行参数-lang=语言标识,以`//@lang=语言 说明`声明指定语言说明 2. 支持多语言,新增执行参数`-lang=语言标识`,以`//@lang=语言 说明`声明指定语言说明
3. 优化Description显示,tag换行显示,引用对象时采用本地说明 3. 优化Description显示,tag换行显示,引用对象时采用本地说明
4. 支持example定义,用`//@example=”或“//@example()`声明,前者不支持空格 4. 支持example定义,用`//@example=”或“//@example()`声明,前者不支持空格
5. 增加path的参数及说明,于请求声明上一行添加注释,例如:`option (http.Get) = "/user/:id";`,上一行添加:`// @query=id @lang=语言标识 @format=string @example=ABC 说明文本`,其中query是必须指定声明,format默认为int 5. 增加path的参数及说明,于请求声明上一行添加注释,例如:`option (http.Get) = "/user/:id";`,上一行添加:`// @query=id @lang=语言标识 @format=string @example=ABC 说明文本`,其中query是必须指定声明,format默认为int
### 2024-10-18 更新
1. 在路由组声明上一行加上注释`@prefix=xxx`即可指定当前protobuf文件生成的swagger的接口前缀为`xxx`,该注释仅文档使用,应与业务代码一致)
```
// @prefix=api
option (http.RouteGroup) = "api";
```
2. 新增执行参数`-host=接口host`,接口host以`http://``https://`开头则指定协议,只填域名则两者都支持