From d7cbf81799df5676c3c4b5ecbeab741e52f4531e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Thu, 20 Feb 2025 16:22:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=A4=BA=E4=BE=8B=E5=80=BC?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=20+=20=E4=BC=98=E5=8C=96schema=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- define/openapi.go | 1 + define/tag.go | 2 + generate.go | 105 ++++++++++++++++++++-------------------------- struct_field.go | 16 +++++++ 4 files changed, 65 insertions(+), 59 deletions(-) diff --git a/define/openapi.go b/define/openapi.go index cdd5523..d361a86 100644 --- a/define/openapi.go +++ b/define/openapi.go @@ -155,6 +155,7 @@ type Property struct { XEnumDescription map[string]string `json:"x-enumDescriptions,omitempty"` // 枚举值描述的扩展, redoc-free支持 Default any `json:"default,omitempty"` // 默认值 : 不同于 JSON Schema,这个值必须符合定义与相同级别的 Schema 对象 中定义的类型,比如 type 是 string,那么 default 可以是 "foo" 但不能是 1。 Description string `json:"description,omitempty"` // 数据描述, CommonMark syntax可以被用来呈现富文本格式. + Example string `json:"example,omitempty"` // 媒体类型的示例。示例对象应该符合此媒体类型的格式, 这里指定的example对象 object is mutually exclusive of the examples object. 而且如果引用的schema也包含示例,在这里指定的example值将会覆盖schema提供的示例。 Maximum *int64 `json:"maximum,omitempty"` // 最大值 Minimum *int64 `json:"minimum,omitempty"` // 最小值 MinLength *int64 `json:"minLength,omitempty"` // 字符串最小长度 diff --git a/define/tag.go b/define/tag.go index 9a5edf3..78ae579 100644 --- a/define/tag.go +++ b/define/tag.go @@ -29,6 +29,8 @@ const ( TagUriTag = "tag" // 接口的tag TagOutputStrict = "output_strict" // 接口数据是否为严格模式 : 严格模式, 响应数据必须是结构体/map,非严格模式返回任意值 TagErrMsg = "err" // 验证失败错误信息tag + TagExample = "example" // 示例值 + TagEg = "eg" // 示例值 TagContentType = "content_type" TagOutputContentType = "output_content_type" TagNameOmitempty = "omitempty" diff --git a/generate.go b/generate.go index 0799cca..5fc8c90 100644 --- a/generate.go +++ b/generate.go @@ -342,13 +342,8 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe convertBaseType, isBaseType := g.realBaseType2SwaggerType(inputType.Field(i).Type.String()) realInputTypeFormat := inputType.Field(i).Type.String() fieldType := inputType.Field(i).Type - /*if inputType.Field(i).Type.Kind() == reflect.Ptr { - fieldType = inputType.Field(i).Type.Elem() - }*/ if isBaseType { // 当做默认基础类型, 默认不会出现 *map *[] - minVal := ValidateRule.Minimum(inputType.Field(i)) - maxVal := ValidateRule.Maximum(inputType.Field(i)) itemParam := &define.PathConfigParameter{ Name: propertyName, In: consts.SwaggerParameterInQuery, @@ -356,24 +351,15 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe Required: ValidateRule.IsRequired(inputType.Field(i)), Deprecated: ParseStructFieldTag.Deprecated(inputType.Field(i)), Schema: &define.Schema{ - Type: convertBaseType, - Format: realInputTypeFormat, - Default: ParseStructFieldTag.GetDefaultValue(inputType.Field(i)), - Enum: ValidateRule.Enum(inputType.Field(i)), - XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)), + Type: convertBaseType, + Format: realInputTypeFormat, }, AllowEmptyValue: false, Style: "", Explode: false, AllowReserved: false, } - if itemParam.Schema.Type == consts.SwaggerDataTypeString { - itemParam.Schema.MinLength = minVal - itemParam.Schema.MaxLength = maxVal - } else { - itemParam.Schema.Minimum = minVal - itemParam.Schema.Maximum = maxVal - } + g.setStructFieldProperty(itemParam.Schema, inputType.Field(i)) baseReqCfg.Parameters = append(baseReqCfg.Parameters, itemParam) continue } @@ -389,6 +375,7 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe Format: realInputTypeFormat, Enum: ValidateRule.Enum(inputType.Field(i)), XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)), + Example: ParseStructFieldTag.GetExampleValue(inputType.Field(i)), }, }) continue @@ -434,6 +421,7 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe Format: realInputTypeFormat, Enum: ValidateRule.Enum(inputType.Field(i)), XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)), + Example: ParseStructFieldTag.GetExampleValue(inputType.Field(i)), }, AllowEmptyValue: false, Style: "", @@ -521,7 +509,6 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in Items: propertyXOf, } } - return schemaName } // 结构体 @@ -554,24 +541,13 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in } else { // 当做默认基础类型, 默认不会出现 *map *[] convertBaseType, _ := g.realBaseType2SwaggerType(inputType.Field(i).Type.String()) - maxVal := ValidateRule.Maximum(inputType.Field(i)) - minVal := ValidateRule.Minimum(inputType.Field(i)) g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{ - Type: convertBaseType, - Format: inputType.Field(i).Type.String(), - Enum: ValidateRule.Enum(inputType.Field(i)), - XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)), - Default: ParseStructFieldTag.GetDefaultValue(inputType.Field(i)), - Description: ParseStructFieldTag.GetParamDesc(inputType.Field(i)), - } - if g.docData.Components.Schemas[schemaName].Properties[propertyName].Type == consts.SwaggerDataTypeString { - g.docData.Components.Schemas[schemaName].Properties[propertyName].MinLength = minVal - g.docData.Components.Schemas[schemaName].Properties[propertyName].MaxLength = maxVal - } else { - g.docData.Components.Schemas[schemaName].Properties[propertyName].Minimum = minVal - g.docData.Components.Schemas[schemaName].Properties[propertyName].Maximum = maxVal + Type: convertBaseType, + Format: inputType.Field(i).Type.String(), } } + // 设置参数各种属性 + g.setStructFieldProperty(g.docData.Components.Schemas[schemaName], inputType.Field(i)) continue } if inputType.Field(i).Type.Kind() == reflect.Struct || @@ -581,10 +557,9 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in if inputType.Field(i).Type.Kind() == reflect.Struct || inputType.Field(i).Type.Kind() == reflect.Map { g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{ - Type: consts.SwaggerDataTypeObject, - Format: inputType.Field(i).Type.String(), - Description: ParseStructFieldTag.GetParamDesc(inputType.Field(i)), - Properties: map[string]*define.Property{}, + Type: consts.SwaggerDataTypeObject, + Format: inputType.Field(i).Type.String(), + Properties: map[string]*define.Property{}, } } else if inputType.Field(i).Type.Kind() == reflect.Array || inputType.Field(i).Type.Kind() == reflect.Slice { @@ -600,10 +575,9 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in propertyXOf.Ref = g.getSchemaRef(sliceItemType) } g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{ - Type: consts.SwaggerDataTypeArray, - Format: inputType.Field(i).Type.String(), - Description: ParseStructFieldTag.GetParamDesc(inputType.Field(i)), - Items: propertyXOf, + Type: consts.SwaggerDataTypeArray, + Format: inputType.Field(i).Type.String(), + Items: propertyXOf, } } else { g.AddComponentsSchema(schemaName, propertyName, inputType.Field(i).Type) @@ -611,27 +585,17 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in } else { if inputType.Field(i).Type.Kind() == reflect.Interface { g.docData.Components.Schemas[schemaName].Properties[propertyName] = g.anyTypeConfig(inputType.Field(i)) + g.docData.Components.Schemas[schemaName].Properties[propertyName].Example = ParseStructFieldTag.GetExampleValue(inputType.Field(i)) } else { convertBaseType, _ := g.realBaseType2SwaggerType(inputType.Field(i).Type.String()) - maxVal := ValidateRule.Maximum(inputType.Field(i)) - minVal := ValidateRule.Minimum(inputType.Field(i)) g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{ - Type: convertBaseType, - Format: inputType.Field(i).Type.String(), - Default: ParseStructFieldTag.GetDefaultValue(inputType.Field(i)), - Description: ParseStructFieldTag.GetParamDesc(inputType.Field(i)), - } - if g.docData.Components.Schemas[schemaName].Properties[propertyName].Type == consts.SwaggerDataTypeString { - g.docData.Components.Schemas[schemaName].Properties[propertyName].MinLength = minVal - g.docData.Components.Schemas[schemaName].Properties[propertyName].MaxLength = maxVal - } else { - g.docData.Components.Schemas[schemaName].Properties[propertyName].Minimum = minVal - g.docData.Components.Schemas[schemaName].Properties[propertyName].Maximum = maxVal + Type: convertBaseType, + Format: inputType.Field(i).Type.String(), } } } // 设置参数各种属性 - g.setStructFieldProperty(schemaName, inputType.Field(i)) + g.setStructFieldProperty(g.docData.Components.Schemas[schemaName], inputType.Field(i)) } return schemaName } @@ -686,6 +650,7 @@ func (g *Generate) handleAnonymousField(schemaName string, field reflect.StructF g.docData.Components.Schemas[schemaName].Properties[paramName] = &define.Property{ Type: baseConvertType, Format: itemField.Type.String(), + Example: ParseStructFieldTag.GetExampleValue(itemField), Enum: ValidateRule.Enum(itemField), XEnumDescription: ParseStructFieldTag.EnumDescription(itemField), Default: ParseStructFieldTag.GetDefaultValue(handleType.Field(i)), @@ -775,12 +740,34 @@ func (g *Generate) realBaseType2SwaggerType(realType string) (string, bool) { // Author : go_developer@163.com<白茶清欢> // // Date : 16:13 2025/2/13 -func (g *Generate) setStructFieldProperty(schemaName string, structField reflect.StructField) { +func (g *Generate) setStructFieldProperty(schema *define.Schema, structField reflect.StructField) { paramName := ParseStructFieldTag.GetParamName(structField) - if ValidateRule.IsRequired(structField) { - g.docData.Components.Schemas[schemaName].Required = append(g.docData.Components.Schemas[schemaName].Required, paramName) + if paramName == "" || paramName == "-" { + return + } + isRequired := ValidateRule.IsRequired(structField) + enum := ValidateRule.Enum(structField) + xEnumDescription := ParseStructFieldTag.EnumDescription(structField) + example := ParseStructFieldTag.GetExampleValue(structField) + description := ParseStructFieldTag.GetParamDesc(structField) + maxVal := ValidateRule.Maximum(structField) + minVal := ValidateRule.Minimum(structField) + if nil != schema { + if isRequired { + schema.Required = append(schema.Required, paramName) + } + if schema.Properties[paramName].Type == consts.SwaggerDataTypeString { + schema.Properties[paramName].MinLength = minVal + schema.Properties[paramName].MaxLength = maxVal + } else { + schema.Properties[paramName].Minimum = minVal + schema.Properties[paramName].Maximum = maxVal + } + schema.Properties[paramName].Enum = enum + schema.Properties[paramName].XEnumDescription = xEnumDescription + schema.Properties[paramName].Example = example + schema.Properties[paramName].Description = description } - g.docData.Components.Schemas[schemaName].Properties[ParseStructFieldTag.GetParamName(structField)].Enum = ValidateRule.Enum(structField) } // parseBaseUriConfig 通过Meta字段解析Uri基础配置信息 diff --git a/struct_field.go b/struct_field.go index 913f60b..318c0db 100644 --- a/struct_field.go +++ b/struct_field.go @@ -178,3 +178,19 @@ func (psf parseStructFieldTag) EnumDescription(structField reflect.StructField) } return res } + +// GetExampleValue 示例值 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 14:42 2025/2/20 +func (psf parseStructFieldTag) GetExampleValue(structField reflect.StructField) string { + descTagList := []string{define.TagEg, define.TagExample} + for _, tag := range descTagList { + tagVal := structField.Tag.Get(tag) + if tagVal != "" { + return strings.ReplaceAll(tagVal, "###", "`") + } + } + return "" +}