From c9604091f2a07f800c21ab0a93425f62a2cd943a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Fri, 14 Feb 2025 18:22:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96GET=E7=B1=BB=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E6=96=87=E6=A1=A3=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generate.go | 172 +++++++++++++++++++++++++++++++----------------- parser_test.go | 15 ++++- struct_field.go | 6 +- 3 files changed, 129 insertions(+), 64 deletions(-) diff --git a/generate.go b/generate.go index b1f6dae..a185ee1 100644 --- a/generate.go +++ b/generate.go @@ -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 diff --git a/parser_test.go b/parser_test.go index 1cb2be7..93348dd 100644 --- a/parser_test.go +++ b/parser_test.go @@ -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)) } diff --git a/struct_field.go b/struct_field.go index 42f40d3..f6bb6e3 100644 --- a/struct_field.go +++ b/struct_field.go @@ -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 }