增加示例值解析 + 优化schema属性配置

This commit is contained in:
白茶清欢 2025-02-20 16:22:23 +08:00
parent bd7f6d2cfd
commit d7cbf81799
4 changed files with 65 additions and 59 deletions

View File

@ -155,6 +155,7 @@ type Property struct {
XEnumDescription map[string]string `json:"x-enumDescriptions,omitempty"` // 枚举值描述的扩展, redoc-free支持 XEnumDescription map[string]string `json:"x-enumDescriptions,omitempty"` // 枚举值描述的扩展, redoc-free支持
Default any `json:"default,omitempty"` // 默认值 : 不同于 JSON Schema这个值必须符合定义与相同级别的 Schema 对象 中定义的类型,比如 type 是 string那么 default 可以是 "foo" 但不能是 1。 Default any `json:"default,omitempty"` // 默认值 : 不同于 JSON Schema这个值必须符合定义与相同级别的 Schema 对象 中定义的类型,比如 type 是 string那么 default 可以是 "foo" 但不能是 1。
Description string `json:"description,omitempty"` // 数据描述, CommonMark syntax可以被用来呈现富文本格式. 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"` // 最大值 Maximum *int64 `json:"maximum,omitempty"` // 最大值
Minimum *int64 `json:"minimum,omitempty"` // 最小值 Minimum *int64 `json:"minimum,omitempty"` // 最小值
MinLength *int64 `json:"minLength,omitempty"` // 字符串最小长度 MinLength *int64 `json:"minLength,omitempty"` // 字符串最小长度

View File

@ -29,6 +29,8 @@ const (
TagUriTag = "tag" // 接口的tag TagUriTag = "tag" // 接口的tag
TagOutputStrict = "output_strict" // 接口数据是否为严格模式 : 严格模式, 响应数据必须是结构体/map非严格模式返回任意值 TagOutputStrict = "output_strict" // 接口数据是否为严格模式 : 严格模式, 响应数据必须是结构体/map非严格模式返回任意值
TagErrMsg = "err" // 验证失败错误信息tag TagErrMsg = "err" // 验证失败错误信息tag
TagExample = "example" // 示例值
TagEg = "eg" // 示例值
TagContentType = "content_type" TagContentType = "content_type"
TagOutputContentType = "output_content_type" TagOutputContentType = "output_content_type"
TagNameOmitempty = "omitempty" TagNameOmitempty = "omitempty"

View File

@ -342,13 +342,8 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe
convertBaseType, isBaseType := g.realBaseType2SwaggerType(inputType.Field(i).Type.String()) convertBaseType, isBaseType := g.realBaseType2SwaggerType(inputType.Field(i).Type.String())
realInputTypeFormat := inputType.Field(i).Type.String() realInputTypeFormat := inputType.Field(i).Type.String()
fieldType := inputType.Field(i).Type fieldType := inputType.Field(i).Type
/*if inputType.Field(i).Type.Kind() == reflect.Ptr {
fieldType = inputType.Field(i).Type.Elem()
}*/
if isBaseType { if isBaseType {
// 当做默认基础类型, 默认不会出现 *map *[] // 当做默认基础类型, 默认不会出现 *map *[]
minVal := ValidateRule.Minimum(inputType.Field(i))
maxVal := ValidateRule.Maximum(inputType.Field(i))
itemParam := &define.PathConfigParameter{ itemParam := &define.PathConfigParameter{
Name: propertyName, Name: propertyName,
In: consts.SwaggerParameterInQuery, In: consts.SwaggerParameterInQuery,
@ -356,24 +351,15 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe
Required: ValidateRule.IsRequired(inputType.Field(i)), Required: ValidateRule.IsRequired(inputType.Field(i)),
Deprecated: ParseStructFieldTag.Deprecated(inputType.Field(i)), Deprecated: ParseStructFieldTag.Deprecated(inputType.Field(i)),
Schema: &define.Schema{ Schema: &define.Schema{
Type: convertBaseType, Type: convertBaseType,
Format: realInputTypeFormat, Format: realInputTypeFormat,
Default: ParseStructFieldTag.GetDefaultValue(inputType.Field(i)),
Enum: ValidateRule.Enum(inputType.Field(i)),
XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)),
}, },
AllowEmptyValue: false, AllowEmptyValue: false,
Style: "", Style: "",
Explode: false, Explode: false,
AllowReserved: false, AllowReserved: false,
} }
if itemParam.Schema.Type == consts.SwaggerDataTypeString { g.setStructFieldProperty(itemParam.Schema, inputType.Field(i))
itemParam.Schema.MinLength = minVal
itemParam.Schema.MaxLength = maxVal
} else {
itemParam.Schema.Minimum = minVal
itemParam.Schema.Maximum = maxVal
}
baseReqCfg.Parameters = append(baseReqCfg.Parameters, itemParam) baseReqCfg.Parameters = append(baseReqCfg.Parameters, itemParam)
continue continue
} }
@ -389,6 +375,7 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe
Format: realInputTypeFormat, Format: realInputTypeFormat,
Enum: ValidateRule.Enum(inputType.Field(i)), Enum: ValidateRule.Enum(inputType.Field(i)),
XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)), XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)),
Example: ParseStructFieldTag.GetExampleValue(inputType.Field(i)),
}, },
}) })
continue continue
@ -434,6 +421,7 @@ func (g *Generate) ParseReadConfigParam(requestCfg *define.UriBaseConfig, baseRe
Format: realInputTypeFormat, Format: realInputTypeFormat,
Enum: ValidateRule.Enum(inputType.Field(i)), Enum: ValidateRule.Enum(inputType.Field(i)),
XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)), XEnumDescription: ParseStructFieldTag.EnumDescription(inputType.Field(i)),
Example: ParseStructFieldTag.GetExampleValue(inputType.Field(i)),
}, },
AllowEmptyValue: false, AllowEmptyValue: false,
Style: "", Style: "",
@ -521,7 +509,6 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in
Items: propertyXOf, Items: propertyXOf,
} }
} }
return schemaName return schemaName
} }
// 结构体 // 结构体
@ -554,24 +541,13 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in
} else { } else {
// 当做默认基础类型, 默认不会出现 *map *[] // 当做默认基础类型, 默认不会出现 *map *[]
convertBaseType, _ := g.realBaseType2SwaggerType(inputType.Field(i).Type.String()) 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{ g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{
Type: convertBaseType, Type: convertBaseType,
Format: inputType.Field(i).Type.String(), 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
} }
} }
// 设置参数各种属性
g.setStructFieldProperty(g.docData.Components.Schemas[schemaName], inputType.Field(i))
continue continue
} }
if inputType.Field(i).Type.Kind() == reflect.Struct || 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 || if inputType.Field(i).Type.Kind() == reflect.Struct ||
inputType.Field(i).Type.Kind() == reflect.Map { inputType.Field(i).Type.Kind() == reflect.Map {
g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{ g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{
Type: consts.SwaggerDataTypeObject, Type: consts.SwaggerDataTypeObject,
Format: inputType.Field(i).Type.String(), Format: inputType.Field(i).Type.String(),
Description: ParseStructFieldTag.GetParamDesc(inputType.Field(i)), Properties: map[string]*define.Property{},
Properties: map[string]*define.Property{},
} }
} else if inputType.Field(i).Type.Kind() == reflect.Array || } else if inputType.Field(i).Type.Kind() == reflect.Array ||
inputType.Field(i).Type.Kind() == reflect.Slice { 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) propertyXOf.Ref = g.getSchemaRef(sliceItemType)
} }
g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{ g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{
Type: consts.SwaggerDataTypeArray, Type: consts.SwaggerDataTypeArray,
Format: inputType.Field(i).Type.String(), Format: inputType.Field(i).Type.String(),
Description: ParseStructFieldTag.GetParamDesc(inputType.Field(i)), Items: propertyXOf,
Items: propertyXOf,
} }
} else { } else {
g.AddComponentsSchema(schemaName, propertyName, inputType.Field(i).Type) g.AddComponentsSchema(schemaName, propertyName, inputType.Field(i).Type)
@ -611,27 +585,17 @@ func (g *Generate) AddComponentsSchema(rootSchemaName string, pkgPath string, in
} else { } else {
if inputType.Field(i).Type.Kind() == reflect.Interface { 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] = g.anyTypeConfig(inputType.Field(i))
g.docData.Components.Schemas[schemaName].Properties[propertyName].Example = ParseStructFieldTag.GetExampleValue(inputType.Field(i))
} else { } else {
convertBaseType, _ := g.realBaseType2SwaggerType(inputType.Field(i).Type.String()) 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{ g.docData.Components.Schemas[schemaName].Properties[propertyName] = &define.Property{
Type: convertBaseType, Type: convertBaseType,
Format: inputType.Field(i).Type.String(), 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
} }
} }
} }
// 设置参数各种属性 // 设置参数各种属性
g.setStructFieldProperty(schemaName, inputType.Field(i)) g.setStructFieldProperty(g.docData.Components.Schemas[schemaName], inputType.Field(i))
} }
return schemaName return schemaName
} }
@ -686,6 +650,7 @@ func (g *Generate) handleAnonymousField(schemaName string, field reflect.StructF
g.docData.Components.Schemas[schemaName].Properties[paramName] = &define.Property{ g.docData.Components.Schemas[schemaName].Properties[paramName] = &define.Property{
Type: baseConvertType, Type: baseConvertType,
Format: itemField.Type.String(), Format: itemField.Type.String(),
Example: ParseStructFieldTag.GetExampleValue(itemField),
Enum: ValidateRule.Enum(itemField), Enum: ValidateRule.Enum(itemField),
XEnumDescription: ParseStructFieldTag.EnumDescription(itemField), XEnumDescription: ParseStructFieldTag.EnumDescription(itemField),
Default: ParseStructFieldTag.GetDefaultValue(handleType.Field(i)), Default: ParseStructFieldTag.GetDefaultValue(handleType.Field(i)),
@ -775,12 +740,34 @@ func (g *Generate) realBaseType2SwaggerType(realType string) (string, bool) {
// Author : go_developer@163.com<白茶清欢> // Author : go_developer@163.com<白茶清欢>
// //
// Date : 16:13 2025/2/13 // 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) paramName := ParseStructFieldTag.GetParamName(structField)
if ValidateRule.IsRequired(structField) { if paramName == "" || paramName == "-" {
g.docData.Components.Schemas[schemaName].Required = append(g.docData.Components.Schemas[schemaName].Required, 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基础配置信息 // parseBaseUriConfig 通过Meta字段解析Uri基础配置信息

View File

@ -178,3 +178,19 @@ func (psf parseStructFieldTag) EnumDescription(structField reflect.StructField)
} }
return res 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 ""
}