优化GET类请求文档生成

This commit is contained in:
白茶清欢 2025-02-14 18:22:53 +08:00
parent f51388c1d6
commit c9604091f2
3 changed files with 129 additions and 64 deletions

View File

@ -184,6 +184,81 @@ func (g *Generate) AddApiFromInAndOut(paramType reflect.Type, resultType reflect
if _, exist := g.docData.Paths[baseCfg.Uri]; !exist {
g.docData.Paths[baseCfg.Uri] = &define.PathConfig{}
}
// 接口文档初始化
cfg := g.getApiDocBaseCfg(baseCfg, paramType)
paramMethod := []string{
http.MethodGet, http.MethodHead, http.MethodConnect, http.MethodOptions, http.MethodTrace,
}
if wrapper.ArrayType(paramMethod).Has(baseCfg.Method) >= 0 {
cfg.RequestBody = nil // get类请求没有request body
// 参数解析
g.ParseReadConfigParam(baseCfg, cfg, paramType)
} else {
// post类解析
paramSchemaName := g.AddComponentsSchema("", paramType.PkgPath(), paramType)
for _, itemType := range baseCfg.ContentType {
cfg.RequestBody.Content[itemType] = &define.Media{
Schema: &define.Schema{
Ref: g.getSchemaRef(paramSchemaName),
},
Example: "",
Examples: nil,
Encoding: nil,
}
}
}
// 无论什么请求, 对于result解析逻辑一致
resultSchemaName := g.AddComponentsSchema("", resultType.PkgPath(), resultType)
for _, itemOutputType := range baseCfg.OutputContentType {
cfg.Responses[fmt.Sprintf("%v", http.StatusOK)].Content[itemOutputType] = &define.Media{
Schema: &define.Schema{
Ref: g.getSchemaRef(resultSchemaName),
},
Example: "",
Examples: nil,
Encoding: nil,
}
}
g.setApiDoc(baseCfg, cfg)
return nil
}
// setApiDoc 设置文档配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:13 2025/2/14
func (g *Generate) setApiDoc(baseCfg *define.UriBaseConfig, apiDocCfg *define.PathItemOperationConfig) {
switch baseCfg.Method {
case http.MethodGet:
g.docData.Paths[baseCfg.Uri].Get = apiDocCfg
case http.MethodHead:
g.docData.Paths[baseCfg.Uri].Head = apiDocCfg
case http.MethodPost:
g.docData.Paths[baseCfg.Uri].Post = apiDocCfg
case http.MethodPut:
g.docData.Paths[baseCfg.Uri].Put = apiDocCfg
case http.MethodPatch:
g.docData.Paths[baseCfg.Uri].Patch = apiDocCfg
case http.MethodDelete:
g.docData.Paths[baseCfg.Uri].Delete = apiDocCfg
case http.MethodConnect:
g.docData.Paths[baseCfg.Uri].Connect = apiDocCfg
case http.MethodOptions:
g.docData.Paths[baseCfg.Uri].Options = apiDocCfg
case http.MethodTrace:
g.docData.Paths[baseCfg.Uri].Trace = apiDocCfg
default:
panic("unknown method: " + baseCfg.Method)
}
}
// getApiDocBaseCfg 获取接口文档的基础配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:10 2025/2/14
func (g *Generate) getApiDocBaseCfg(baseCfg *define.UriBaseConfig, paramType reflect.Type) *define.PathItemOperationConfig {
defaultPkgPath := wrapper.String(strings.TrimLeft(baseCfg.Uri, "/")).SnakeCaseToCamel()
cfg := &define.PathItemOperationConfig{
Tags: baseCfg.TagList,
@ -227,63 +302,7 @@ func (g *Generate) AddApiFromInAndOut(paramType reflect.Type, resultType reflect
})
}
}
paramMethod := []string{
http.MethodGet, http.MethodHead, http.MethodConnect, http.MethodOptions, http.MethodTrace,
}
if wrapper.ArrayType(paramMethod).Has(baseCfg.Method) >= 0 {
cfg.RequestBody = nil // get类请求没有request body
// Get类请求, TODO : get类解析
// 参数解析
g.ParseReadConfigParam(baseCfg, cfg, paramType)
} else {
// post类解析
paramSchemaName := g.AddComponentsSchema("", paramType.PkgPath(), paramType)
for _, itemType := range baseCfg.ContentType {
cfg.RequestBody.Content[itemType] = &define.Media{
Schema: &define.Schema{
Ref: g.getSchemaRef(paramSchemaName),
},
Example: "",
Examples: nil,
Encoding: nil,
}
}
}
// 无论什么请求, 对于result解析逻辑一致
resultSchemaName := g.AddComponentsSchema("", resultType.PkgPath(), resultType)
for _, itemOutputType := range baseCfg.OutputContentType {
cfg.Responses[fmt.Sprintf("%v", http.StatusOK)].Content[itemOutputType] = &define.Media{
Schema: &define.Schema{
Ref: g.getSchemaRef(resultSchemaName),
},
Example: "",
Examples: nil,
Encoding: nil,
}
}
switch baseCfg.Method {
case http.MethodGet:
g.docData.Paths[baseCfg.Uri].Get = cfg
case http.MethodHead:
g.docData.Paths[baseCfg.Uri].Head = cfg
case http.MethodPost:
g.docData.Paths[baseCfg.Uri].Post = cfg
case http.MethodPut:
g.docData.Paths[baseCfg.Uri].Put = cfg
case http.MethodPatch:
g.docData.Paths[baseCfg.Uri].Patch = cfg
case http.MethodDelete:
g.docData.Paths[baseCfg.Uri].Delete = cfg
case http.MethodConnect:
g.docData.Paths[baseCfg.Uri].Connect = cfg
case http.MethodOptions:
g.docData.Paths[baseCfg.Uri].Options = cfg
case http.MethodTrace:
g.docData.Paths[baseCfg.Uri].Trace = cfg
default:
panic("unknown method: " + baseCfg.Method)
}
return nil
return cfg
}
// ParseReadConfigParam 解析get类请求参数
@ -298,6 +317,9 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe
if inputType.Kind() != reflect.Struct {
panic(requestCfg.Uri + " : request param not struct")
}
if nil == baseReqCfg.Parameters {
baseReqCfg.Parameters = make([]*define.PathConfigParameter, 0)
}
for i := 0; i < inputType.NumField(); i++ {
propertyName := ParseStructField.GetParamName(inputType.Field(i))
if propertyName == "-" {
@ -315,14 +337,28 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe
fieldType.Kind() == reflect.Slice {
if convertType := g.realBaseType2SwaggerType(fieldType.String()); !strings.HasPrefix(convertType, "[]") && convertType != inputType.Field(i).Type.Kind().String() {
// 针对基础类型指针
baseReqCfg.Parameters = append(baseReqCfg.Parameters, &define.PathConfigParameter{
Name: ParseStructField.GetParamName(inputType.Field(i)),
In: consts.SwaggerParameterInQuery,
Description: ParseStructField.GetParamDesc(inputType.Field(i)),
Required: ValidateRule.IsRequired(inputType.Field(i)),
Deprecated: ParseStructField.Deprecated(inputType.Field(i)),
Schema: &define.Schema{
Type: g.realBaseType2SwaggerType(inputType.Field(i).Type.String()),
Items: nil,
Ref: "",
Format: realInputTypeFormat,
},
AllowEmptyValue: false,
Style: "",
Explode: false,
AllowReserved: false,
Ref: "",
})
continue
}
} else {
if nil == g.docData.Paths[requestCfg.Uri].Get {
g.docData.Paths[requestCfg.Uri].Get = &define.PathItemOperationConfig{}
}
g.docData.Paths[requestCfg.Uri].Get.Parameters = append(g.docData.Paths[requestCfg.Uri].Get.Parameters, &define.PathConfigParameter{
baseReqCfg.Parameters = append(baseReqCfg.Parameters, &define.PathConfigParameter{
Name: ParseStructField.GetParamName(inputType.Field(i)),
In: consts.SwaggerParameterInQuery,
Description: ParseStructField.GetParamDesc(inputType.Field(i)),
@ -342,6 +378,18 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe
})
}
}
switch requestCfg.Method {
case http.MethodGet:
g.docData.Paths[requestCfg.Uri].Get = baseReqCfg
case http.MethodHead:
g.docData.Paths[requestCfg.Uri].Head = baseReqCfg
case http.MethodConnect:
g.docData.Paths[requestCfg.Uri].Connect = baseReqCfg
case http.MethodOptions:
g.docData.Paths[requestCfg.Uri].Options = baseReqCfg
case http.MethodTrace:
g.docData.Paths[requestCfg.Uri].Trace = baseReqCfg
}
}
// AddComponentsSchema 添加schema

View File

@ -45,6 +45,11 @@ func Test_parser_Openapi3(t *testing.T) {
Name string `json:"name" d:"zhang" desc:"用户姓名" binding:"required"`
Age string `json:"age" d:"18" desc:"年龄" binding:"required,oneof=12 13 18 90"`
}
type UserHead struct {
Meta `json:"-" deprecated:"false" path:"/user/detail/head/{put_user_id}" method:"HEAD" desc:"测试接口" tag:"用户,搜索" content_type:"application/json" output_content_type:"application/json"`
Name string `json:"name" d:"zhang" desc:"用户姓名" binding:"required"`
Age string `json:"age" d:"18" desc:"年龄" binding:"required,oneof=12 13 18 90"`
}
type List struct {
Total int64 `json:"total" binding:"required"`
UserList []User `json:"user_list"`
@ -54,11 +59,18 @@ func Test_parser_Openapi3(t *testing.T) {
var fd UserDelete
var up UserPut
var ug UserGet
var uh UserHead
g := NewOpenapiDoc(nil, []*define.ServerItem{
&define.ServerItem{
Url: "http://127.0.0.1/v1",
Description: "v1接口",
Variables: nil,
Variables: map[string]*define.ServerItemVariable{
"test": &define.ServerItemVariable{
Default: "123456",
Description: "1111",
Enum: nil,
},
},
},
&define.ServerItem{
Url: "http://127.0.0.1/v2",
@ -70,6 +82,7 @@ func Test_parser_Openapi3(t *testing.T) {
g.AddApiFromInAndOut(reflect.TypeOf(fd), reflect.TypeOf(o))
g.AddApiFromInAndOut(reflect.TypeOf(up), reflect.TypeOf(o))
g.AddApiFromInAndOut(reflect.TypeOf(ug), reflect.TypeOf(o))
g.AddApiFromInAndOut(reflect.TypeOf(uh), reflect.TypeOf(o))
byteData, _ := json.Marshal(g.docData)
fmt.Println(string(byteData))
}

View File

@ -139,5 +139,9 @@ func (psf parseStructField) Summary(structField reflect.StructField) string {
return tagVal
}
}
return psf.GetParamName(structField)
paramName := psf.GetParamName(structField)
if paramName == "-" {
return ""
}
return paramName
}