github.com/wangyougui/gf/v2@v2.6.5/net/goai/goai_shema_ref.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package goai 8 9 import ( 10 "fmt" 11 "reflect" 12 13 "github.com/wangyougui/gf/v2/internal/json" 14 "github.com/wangyougui/gf/v2/text/gstr" 15 "github.com/wangyougui/gf/v2/util/gconv" 16 "github.com/wangyougui/gf/v2/util/gtag" 17 ) 18 19 type SchemaRefs []SchemaRef 20 21 type SchemaRef struct { 22 Ref string 23 Value *Schema 24 } 25 26 // isEmbeddedStructDefinition checks and returns whether given golang type is embedded struct definition, like: 27 // 28 // struct A struct{ 29 // B struct{ 30 // // ... 31 // } 32 // } 33 // 34 // The `B` in `A` is called `embedded struct definition`. 35 func (oai *OpenApiV3) isEmbeddedStructDefinition(golangType reflect.Type) bool { 36 s := golangType.String() 37 return gstr.Contains(s, `struct {`) 38 } 39 40 // newSchemaRefWithGolangType creates a new Schema and returns its SchemaRef. 41 func (oai *OpenApiV3) newSchemaRefWithGolangType(golangType reflect.Type, tagMap map[string]string) (*SchemaRef, error) { 42 var ( 43 err error 44 oaiType = oai.golangTypeToOAIType(golangType) 45 oaiFormat = oai.golangTypeToOAIFormat(golangType) 46 typeName = golangType.Name() 47 pkgPath = golangType.PkgPath() 48 schemaRef = &SchemaRef{} 49 schema = &Schema{ 50 Type: oaiType, 51 Format: oaiFormat, 52 XExtensions: make(XExtensions), 53 } 54 ) 55 if pkgPath == "" { 56 switch golangType.Kind() { 57 case reflect.Ptr, reflect.Array, reflect.Slice: 58 pkgPath = golangType.Elem().PkgPath() 59 typeName = golangType.Elem().Name() 60 } 61 } 62 63 // Type enums. 64 var typeId = fmt.Sprintf(`%s.%s`, pkgPath, typeName) 65 if enums := gtag.GetEnumsByType(typeId); enums != "" { 66 schema.Enum = make([]interface{}, 0) 67 if err = json.Unmarshal([]byte(enums), &schema.Enum); err != nil { 68 return nil, err 69 } 70 } 71 72 if len(tagMap) > 0 { 73 if err := oai.tagMapToSchema(tagMap, schema); err != nil { 74 return nil, err 75 } 76 } 77 schemaRef.Value = schema 78 switch oaiType { 79 case TypeString, TypeFile: 80 // Nothing to do. 81 case TypeInteger: 82 if schemaRef.Value.Default != nil { 83 schemaRef.Value.Default = gconv.Int64(schemaRef.Value.Default) 84 } 85 // keep the default value as nil. 86 87 // example value needs to be converted just like default value 88 if schemaRef.Value.Example != nil { 89 schemaRef.Value.Example = gconv.Int64(schemaRef.Value.Example) 90 } 91 // keep the example value as nil. 92 case TypeNumber: 93 if schemaRef.Value.Default != nil { 94 schemaRef.Value.Default = gconv.Float64(schemaRef.Value.Default) 95 } 96 // keep the default value as nil. 97 98 // example value needs to be converted just like default value 99 if schemaRef.Value.Example != nil { 100 schemaRef.Value.Example = gconv.Float64(schemaRef.Value.Example) 101 } 102 // keep the example value as nil. 103 case TypeBoolean: 104 if schemaRef.Value.Default != nil { 105 schemaRef.Value.Default = gconv.Bool(schemaRef.Value.Default) 106 } 107 // keep the default value as nil. 108 109 // example value needs to be converted just like default value 110 if schemaRef.Value.Example != nil { 111 schemaRef.Value.Example = gconv.Bool(schemaRef.Value.Example) 112 } 113 // keep the example value as nil. 114 case 115 TypeArray: 116 subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil) 117 if err != nil { 118 return nil, err 119 } 120 schema.Items = subSchemaRef 121 if len(schema.Enum) > 0 { 122 schema.Items.Value.Enum = schema.Enum 123 schema.Enum = nil 124 } 125 126 case 127 TypeObject: 128 for golangType.Kind() == reflect.Ptr { 129 golangType = golangType.Elem() 130 } 131 switch golangType.Kind() { 132 case reflect.Map: 133 // Specially for map type. 134 subSchemaRef, err := oai.newSchemaRefWithGolangType(golangType.Elem(), nil) 135 if err != nil { 136 return nil, err 137 } 138 schema.AdditionalProperties = subSchemaRef 139 return schemaRef, nil 140 141 case reflect.Interface: 142 // Specially for interface type. 143 var ( 144 structTypeName = oai.golangTypeToSchemaName(golangType) 145 ) 146 if oai.Components.Schemas.Get(structTypeName) == nil { 147 if err := oai.addSchema(reflect.New(golangType).Interface()); err != nil { 148 return nil, err 149 } 150 } 151 schemaRef.Ref = structTypeName 152 schemaRef.Value = nil 153 154 default: 155 golangTypeInstance := reflect.New(golangType).Elem().Interface() 156 if oai.isEmbeddedStructDefinition(golangType) { 157 schema, err = oai.structToSchema(golangTypeInstance) 158 if err != nil { 159 return nil, err 160 } 161 schemaRef.Ref = "" 162 schemaRef.Value = schema 163 } else { 164 var structTypeName = oai.golangTypeToSchemaName(golangType) 165 if oai.Components.Schemas.Get(structTypeName) == nil { 166 if err := oai.addSchema(golangTypeInstance); err != nil { 167 return nil, err 168 } 169 } 170 schemaRef.Ref = structTypeName 171 schemaRef.Value = nil 172 } 173 } 174 } 175 return schemaRef, nil 176 } 177 178 func (r SchemaRef) MarshalJSON() ([]byte, error) { 179 if r.Ref != "" { 180 return formatRefToBytes(r.Ref), nil 181 } 182 return json.Marshal(r.Value) 183 }