Кирилл Горбунов
7a302ce899
Co-authored-by: Gorbunov Kirill Andreevich <kgorbunov@mtsbank.ru> Reviewed-on: #8 Reviewed-by: Василий Толстов <v.tolstov@unistack.org> Co-authored-by: Кирилл Горбунов <kirya_gorbunov_2015@mail.ru> Co-committed-by: Кирилл Горбунов <kirya_gorbunov_2015@mail.ru>
190 lines
6.4 KiB
Go
190 lines
6.4 KiB
Go
package swaggerset
|
||
|
||
import (
|
||
"fmt"
|
||
"reflect"
|
||
"strings"
|
||
|
||
dynamicstruct "github.com/ompluscator/dynamic-struct"
|
||
openapi "go.unistack.org/micro-proto/v4/openapiv3"
|
||
)
|
||
|
||
type Message struct {
|
||
Type string
|
||
Request httpRequest
|
||
Response interface{}
|
||
}
|
||
|
||
type httpRequest struct {
|
||
Header interface{}
|
||
Body interface{}
|
||
}
|
||
|
||
func handleOperation(operation *openapi.Operation, doc *openapi.Document) (reqParam, reqBody, rsp interface{}) {
|
||
// Обработка параметров (GET)
|
||
if len(operation.Parameters) > 0 {
|
||
paramsStruct := dynamicstruct.NewStruct()
|
||
for _, paramRef := range operation.Parameters {
|
||
var param *openapi.Parameter
|
||
param = paramRef.GetParameter()
|
||
fieldName := capitalize(param.Name)
|
||
jsonName := strings.ToLower(param.Name[:1]) + param.Name[1:]
|
||
goType := getGoType(doc, param.Schema)
|
||
|
||
// В зависимости от того, где параметр находится (header, query, path, etc.), добавляем соответствующий тег
|
||
switch param.In {
|
||
case "query":
|
||
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s" query:"%s"`, jsonName, jsonName))
|
||
case "header":
|
||
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s" header:"%s"`, jsonName, jsonName))
|
||
default:
|
||
paramsStruct = paramsStruct.AddField(fieldName, goType, fmt.Sprintf(`json:"%s"`, jsonName))
|
||
}
|
||
}
|
||
// Получили структуру запроса для методов, где есть параметры в header, query, path, etc., добавили теги
|
||
reqParam = paramsStruct.Build().New()
|
||
}
|
||
|
||
// Обработка тела запроса (POST)
|
||
if operation.GetRequestBody() != nil {
|
||
if operation.GetRequestBody().GetRequestBody() != nil {
|
||
bodyFields := buildDynamicStruct(doc, operation.GetRequestBody().GetRequestBody().GetContent().GetAdditionalProperties()[0].GetValue().GetSchema())
|
||
bodyStruct := reflect.StructOf(bodyFields)
|
||
bodyInstance := reflect.New(bodyStruct).Interface()
|
||
// Получили тело запроса
|
||
reqBody = bodyInstance
|
||
}
|
||
if operation.GetRequestBody().GetReference() != nil {
|
||
schemOrRef := findReference(doc, operation.GetRequestBody().GetReference().GetXRef())
|
||
bodyFields := buildDynamicStruct(doc, schemOrRef)
|
||
bodyStruct := reflect.StructOf(bodyFields)
|
||
bodyInstance := reflect.New(bodyStruct).Interface()
|
||
// Получили тело запроса
|
||
reqBody = bodyInstance
|
||
}
|
||
}
|
||
|
||
// Обработка ответов
|
||
for _, rspOrRef := range operation.Responses.ResponseOrReference {
|
||
if rspOrRef.GetValue().GetResponse() != nil {
|
||
for _, prop := range rspOrRef.Value.GetResponse().GetContent().GetAdditionalProperties() {
|
||
responseFields := buildDynamicStruct(doc, prop.GetValue().GetSchema())
|
||
responseStruct := reflect.StructOf(responseFields)
|
||
responseInstance := reflect.New(responseStruct).Interface()
|
||
// Получили структуру ответа
|
||
rsp = responseInstance
|
||
}
|
||
}
|
||
if rspOrRef.GetValue().GetReference() != nil {
|
||
schemaOrRef := findReference(doc, rspOrRef.GetValue().GetReference().GetXRef())
|
||
responseFields := buildDynamicStruct(doc, schemaOrRef)
|
||
responseStruct := reflect.StructOf(responseFields)
|
||
responseInstance := reflect.New(responseStruct).Interface()
|
||
// Получили структуру ответа
|
||
rsp = responseInstance
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// Рекурсивное создание структуры из схемы с учетом $ref
|
||
func buildDynamicStruct(doc *openapi.Document, schemaOrRef *openapi.SchemaOrReference) []reflect.StructField {
|
||
var sfields []reflect.StructField
|
||
var schema *openapi.Schema
|
||
if schemaOrRef.GetSchema() != nil {
|
||
schema = schemaOrRef.GetSchema()
|
||
}
|
||
if schemaOrRef.GetReference() != nil {
|
||
name := strings.Split(schemaOrRef.GetReference().GetXRef(), "#/components/schemas/")[1]
|
||
fieldName := capitalize(name)
|
||
subBuilder := buildDynamicStruct(doc, findReference(doc, schemaOrRef.GetReference().GetXRef()))
|
||
sfield := reflect.StructField{
|
||
Name: fieldName,
|
||
Type: reflect.StructOf(subBuilder),
|
||
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, name)),
|
||
}
|
||
sfields = append(sfields, sfield)
|
||
}
|
||
|
||
for _, prop := range schema.GetProperties().GetAdditionalProperties() {
|
||
fieldName := capitalize(prop.GetName())
|
||
if prop.GetValue().GetReference() != nil {
|
||
subBuilder := buildDynamicStruct(doc, prop.GetValue())
|
||
|
||
sfield := reflect.StructField{
|
||
Name: fieldName,
|
||
Type: reflect.StructOf(subBuilder),
|
||
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, prop.GetName())),
|
||
}
|
||
|
||
sfields = append(sfields, sfield)
|
||
}
|
||
if prop.GetValue().GetSchema() != nil {
|
||
sfield := reflect.StructField{
|
||
Name: fieldName,
|
||
Type: reflect.TypeOf(getGoType(doc, prop.GetValue())),
|
||
Tag: reflect.StructTag(fmt.Sprintf(`json:"%s"`, prop.GetName())),
|
||
}
|
||
|
||
sfields = append(sfields, sfield)
|
||
}
|
||
}
|
||
|
||
return sfields
|
||
}
|
||
|
||
func findReference(doc *openapi.Document, ref string) *openapi.SchemaOrReference {
|
||
var result *openapi.SchemaOrReference
|
||
ref = strings.Split(ref, "#/components/schemas/")[1]
|
||
|
||
for _, prop := range doc.Components.Schemas.GetAdditionalProperties() {
|
||
if prop.Name == ref {
|
||
result = prop.Value
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
// Преобразование типа OpenAPI в тип Go
|
||
func getGoType(doc *openapi.Document, schema *openapi.SchemaOrReference) interface{} {
|
||
switch schema.GetSchema().Type {
|
||
case "string":
|
||
return ""
|
||
case "integer":
|
||
return 0
|
||
case "boolean":
|
||
return false
|
||
case "array":
|
||
return []interface{}{}
|
||
case "object":
|
||
return buildDynamicStruct(doc, schema)
|
||
default:
|
||
return nil
|
||
}
|
||
}
|
||
|
||
func capitalize(fieldName string) string {
|
||
if fieldName == "" {
|
||
return fieldName
|
||
}
|
||
// Заменяем точки на подчеркивания для унификации
|
||
fieldName = strings.ReplaceAll(fieldName, ".", "_")
|
||
|
||
// Разделяем строку по подчеркиваниям
|
||
parts := strings.Split(fieldName, "_")
|
||
if len(parts) == 1 {
|
||
return strings.ToUpper(fieldName[:1]) + fieldName[1:]
|
||
}
|
||
|
||
// Обрабатываем каждый фрагмент
|
||
for i := 0; i < len(parts); i++ {
|
||
// Капитализируем первые буквы всех частей, кроме первой
|
||
parts[i] = strings.Title(parts[i]) //cases.Title(language.English).String(parts[i])
|
||
}
|
||
|
||
// Собираем строку обратно, соединяя части без подчеркиваний
|
||
return strings.Join(parts, "")
|
||
}
|