keep sequence in attributes definition for oai.Schemas

This commit is contained in:
John Guo
2022-03-07 19:46:05 +08:00
parent 8a27463e44
commit aea9f6fe18
6 changed files with 138 additions and 73 deletions

View File

@ -47,18 +47,19 @@ func (oai *OpenApiV3) getRequestSchemaRef(in getRequestSchemaRefInput) (*SchemaR
}
var (
dataFieldsPartsArray = gstr.Split(in.RequestDataField, ".")
bizRequestStructSchemaRef, bizRequestStructSchemaRefExist = oai.Components.Schemas[in.BusinessStructName]
schema, err = oai.structToSchema(in.RequestObject)
dataFieldsPartsArray = gstr.Split(in.RequestDataField, ".")
bizRequestStructSchemaRef = oai.Components.Schemas.Get(in.BusinessStructName)
schema, err = oai.structToSchema(in.RequestObject)
)
if err != nil {
return nil, err
}
if in.RequestDataField == "" && bizRequestStructSchemaRefExist {
if in.RequestDataField == "" && bizRequestStructSchemaRef != nil {
// Normal request.
for k, v := range bizRequestStructSchemaRef.Value.Properties {
schema.Properties[k] = v
}
bizRequestStructSchemaRef.Value.Properties.Iterator(func(key string, ref SchemaRef) bool {
schema.Properties.Set(key, ref)
return true
})
} else {
// Common request.
structFields, _ := gstructs.Fields(gstructs.FieldsInput{
@ -76,7 +77,7 @@ func (oai *OpenApiV3) getRequestSchemaRef(in getRequestSchemaRefInput) (*SchemaR
if err = oai.tagMapToSchema(structField.TagMap(), bizRequestStructSchemaRef.Value); err != nil {
return nil, err
}
schema.Properties[fieldName] = bizRequestStructSchemaRef
schema.Properties.Set(fieldName, *bizRequestStructSchemaRef)
break
}
default:
@ -90,7 +91,7 @@ func (oai *OpenApiV3) getRequestSchemaRef(in getRequestSchemaRefInput) (*SchemaR
if err != nil {
return nil, err
}
schema.Properties[fieldName] = *schemaRef
schema.Properties.Set(fieldName, *schemaRef)
break
}
}

View File

@ -51,18 +51,19 @@ func (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*Schem
}
var (
dataFieldsPartsArray = gstr.Split(in.CommonResponseDataField, ".")
bizResponseStructSchemaRef, bizResponseStructSchemaRefExist = oai.Components.Schemas[in.BusinessStructName]
schema, err = oai.structToSchema(in.CommonResponseObject)
dataFieldsPartsArray = gstr.Split(in.CommonResponseDataField, ".")
bizResponseStructSchemaRef = oai.Components.Schemas.Get(in.BusinessStructName)
schema, err = oai.structToSchema(in.CommonResponseObject)
)
if err != nil {
return nil, err
}
if in.CommonResponseDataField == "" && bizResponseStructSchemaRefExist {
if in.CommonResponseDataField == "" && bizResponseStructSchemaRef != nil {
// Normal response.
for k, v := range bizResponseStructSchemaRef.Value.Properties {
schema.Properties[k] = v
}
bizResponseStructSchemaRef.Value.Properties.Iterator(func(key string, ref SchemaRef) bool {
schema.Properties.Set(key, ref)
return true
})
} else {
// Common response.
structFields, _ := gstructs.Fields(gstructs.FieldsInput{
@ -80,7 +81,7 @@ func (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*Schem
if err = oai.tagMapToSchema(structField.TagMap(), bizResponseStructSchemaRef.Value); err != nil {
return nil, err
}
schema.Properties[fieldName] = bizResponseStructSchemaRef
schema.Properties.Set(fieldName, *bizResponseStructSchemaRef)
break
}
default:
@ -95,7 +96,7 @@ func (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*Schem
if err != nil {
return nil, err
}
schema.Properties[fieldName] = *schemaRef
schema.Properties.Set(fieldName, *schemaRef)
break
}
}

View File

@ -9,6 +9,7 @@ package goai
import (
"reflect"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/os/gstructs"
@ -18,8 +19,6 @@ import (
"github.com/gogf/gf/v2/util/gvalid"
)
type Schemas map[string]SchemaRef
// Schema is specified by OpenAPI/Swagger 3.0 standard.
type Schema struct {
OneOf SchemaRefs `json:"oneOf,omitempty" yaml:"oneOf,omitempty"`
@ -78,8 +77,8 @@ func (oai *OpenApiV3) addSchema(object ...interface{}) error {
}
func (oai *OpenApiV3) doAddSchemaSingle(object interface{}) error {
if oai.Components.Schemas == nil {
oai.Components.Schemas = map[string]SchemaRef{}
if oai.Components.Schemas.refs == nil {
oai.Components.Schemas.refs = gmap.NewListMap()
}
var (
@ -88,21 +87,21 @@ func (oai *OpenApiV3) doAddSchemaSingle(object interface{}) error {
)
// Already added.
if _, ok := oai.Components.Schemas[structTypeName]; ok {
if oai.Components.Schemas.Get(structTypeName) != nil {
return nil
}
// Take the holder first.
oai.Components.Schemas[structTypeName] = SchemaRef{}
oai.Components.Schemas.Set(structTypeName, SchemaRef{})
schema, err := oai.structToSchema(object)
if err != nil {
return err
}
oai.Components.Schemas[structTypeName] = SchemaRef{
oai.Components.Schemas.Set(structTypeName, SchemaRef{
Ref: "",
Value: schema,
}
})
return nil
}
@ -111,7 +110,7 @@ func (oai *OpenApiV3) structToSchema(object interface{}) (*Schema, error) {
var (
tagMap = gmeta.Data(object)
schema = &Schema{
Properties: map[string]SchemaRef{},
Properties: createSchemas(),
}
)
if len(tagMap) > 0 {
@ -153,7 +152,7 @@ func (oai *OpenApiV3) structToSchema(object interface{}) (*Schema, error) {
if err != nil {
return nil, err
}
schema.Properties[fieldName] = *schemaRef
schema.Properties.Set(fieldName, *schemaRef)
}
return schema, nil
}

View File

@ -70,7 +70,7 @@ func (oai *OpenApiV3) newSchemaRefWithGolangType(golangType reflect.Type, tagMap
var (
structTypeName = oai.golangTypeToSchemaName(golangType)
)
if _, ok := oai.Components.Schemas[structTypeName]; !ok {
if oai.Components.Schemas.Get(structTypeName) == nil {
if err := oai.addSchema(reflect.New(golangType).Interface()); err != nil {
return nil, err
}
@ -81,7 +81,7 @@ func (oai *OpenApiV3) newSchemaRefWithGolangType(golangType reflect.Type, tagMap
default:
// Normal struct object.
var structTypeName = oai.golangTypeToSchemaName(golangType)
if _, ok := oai.Components.Schemas[structTypeName]; !ok {
if oai.Components.Schemas.Get(structTypeName) == nil {
if err := oai.addSchema(reflect.New(golangType).Elem().Interface()); err != nil {
return nil, err
}

View File

@ -0,0 +1,64 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package goai
import (
"github.com/gogf/gf/v2/container/gmap"
)
type Schemas struct {
refs *gmap.ListMap
}
func createSchemas() Schemas {
return Schemas{
refs: gmap.NewListMap(),
}
}
func (s *Schemas) init() {
if s.refs == nil {
s.refs = gmap.NewListMap()
}
}
func (s Schemas) Get(name string) *SchemaRef {
s.init()
value := s.refs.Get(name)
if value != nil {
ref := value.(SchemaRef)
return &ref
}
return nil
}
func (s Schemas) Set(name string, ref SchemaRef) {
s.init()
s.refs.Set(name, ref)
}
func (s Schemas) Map() map[string]SchemaRef {
s.init()
m := make(map[string]SchemaRef)
s.refs.Iterator(func(key, value interface{}) bool {
m[key.(string)] = value.(SchemaRef)
return true
})
return m
}
func (s Schemas) Iterator(f func(key string, ref SchemaRef) bool) {
s.init()
s.refs.Iterator(func(key, value interface{}) bool {
return f(key.(string), value.(SchemaRef))
})
}
func (s Schemas) MarshalJSON() ([]byte, error) {
s.init()
return s.refs.MarshalJSON()
}

View File

@ -48,14 +48,14 @@ func Test_Basic(t *testing.T) {
})
t.AssertNil(err)
// Schema asserts.
t.Assert(len(oai.Components.Schemas), 2)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Type, goai.TypeObject)
t.Assert(len(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Properties), 7)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Properties[`appId`].Value.Type, goai.TypeNumber)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Properties[`resourceId`].Value.Type, goai.TypeString)
t.Assert(len(oai.Components.Schemas.Map()), 2)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Type, goai.TypeObject)
t.Assert(len(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Properties.Map()), 7)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Properties.Get(`appId`).Value.Type, goai.TypeNumber)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Properties.Get(`resourceId`).Value.Type, goai.TypeString)
t.Assert(len(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`].Value.Properties), 3)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`].Value.Properties[`Params`].Value.Type, goai.TypeArray)
t.Assert(len(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`).Value.Properties.Map()), 3)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`).Value.Properties.Get(`Params`).Value.Type, goai.TypeArray)
})
}
@ -108,14 +108,14 @@ func TestOpenApiV3_Add(t *testing.T) {
t.AssertNil(err)
// fmt.Println(oai.String())
// Schema asserts.
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Type, goai.TypeObject)
t.Assert(len(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Properties), 7)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Properties[`appId`].Value.Type, goai.TypeNumber)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].Value.Properties[`resourceId`].Value.Type, goai.TypeString)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Type, goai.TypeObject)
t.Assert(len(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Properties.Map()), 7)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Properties.Get(`appId`).Value.Type, goai.TypeNumber)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).Value.Properties.Get(`resourceId`).Value.Type, goai.TypeString)
t.Assert(len(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`].Value.Properties), 3)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`].Value.Properties[`Params`].Value.Type, goai.TypeArray)
t.Assert(len(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`).Value.Properties.Map()), 3)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.SetSpecInfo`).Value.Properties.Get(`Params`).Value.Type, goai.TypeArray)
// Paths.
t.Assert(len(oai.Paths), 1)
@ -158,9 +158,9 @@ func TestOpenApiV3_Add_Recursive(t *testing.T) {
})
t.AssertNil(err)
// Schema asserts.
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CategoryTreeItem`].Value.Type, goai.TypeObject)
t.Assert(len(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CategoryTreeItem`].Value.Properties), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CategoryTreeItem`).Value.Type, goai.TypeObject)
t.Assert(len(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CategoryTreeItem`).Value.Properties.Map()), 3)
})
}
@ -222,7 +222,7 @@ func TestOpenApiV3_Add_AutoDetectIn(t *testing.T) {
fmt.Println(oai.String())
t.Assert(len(oai.Components.Schemas), 2)
t.Assert(len(oai.Components.Schemas.Map()), 2)
t.Assert(len(oai.Paths), 1)
t.AssertNE(oai.Paths[path].Get, nil)
t.Assert(len(oai.Paths[path].Get.Parameters), 3)
@ -274,9 +274,9 @@ func TestOpenApiV3_CommonRequest(t *testing.T) {
})
t.AssertNil(err)
// Schema asserts.
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(len(oai.Paths), 1)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties), 3)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties.Map()), 3)
})
}
@ -319,9 +319,9 @@ func TestOpenApiV3_CommonRequest_WithoutDataField_Setting(t *testing.T) {
t.AssertNil(err)
// Schema asserts.
// fmt.Println(oai.String())
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(len(oai.Paths), 1)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties), 5)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties.Map()), 5)
})
}
@ -359,9 +359,9 @@ func TestOpenApiV3_CommonRequest_EmptyRequest(t *testing.T) {
t.AssertNil(err)
// Schema asserts.
// fmt.Println(oai.String())
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(len(oai.Paths), 1)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties), 3)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties.Map()), 3)
})
}
@ -414,10 +414,10 @@ func TestOpenApiV3_CommonRequest_SubDataField(t *testing.T) {
t.AssertNil(err)
// Schema asserts.
// fmt.Println(oai.String())
t.Assert(len(oai.Components.Schemas), 4)
t.Assert(len(oai.Components.Schemas.Map()), 4)
t.Assert(len(oai.Paths), 1)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties), 1)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties[`Request`].Value.Properties), 4)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties.Map()), 1)
t.Assert(len(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Value.Properties.Get(`Request`).Value.Properties.Map()), 4)
})
}
@ -460,13 +460,13 @@ func TestOpenApiV3_CommonResponse(t *testing.T) {
})
t.AssertNil(err)
//g.Dump(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties)
//g.Dump(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties.Map())
// Schema asserts.
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(len(oai.Paths), 1)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties), 3)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties.Map()), 3)
t.Assert(
oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties["data"].Value.Description,
oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties.Get("data").Value.Description,
`Result data for certain request according API definition`,
)
})
@ -511,9 +511,9 @@ func TestOpenApiV3_CommonResponse_WithoutDataField_Setting(t *testing.T) {
t.AssertNil(err)
// Schema asserts.
fmt.Println(oai.String())
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(len(oai.Paths), 1)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties), 8)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties.Map()), 8)
})
}
@ -551,10 +551,10 @@ func TestOpenApiV3_CommonResponse_EmptyResponse(t *testing.T) {
t.AssertNil(err)
// Schema asserts.
// fmt.Println(oai.String())
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(len(oai.Paths), 1)
t.Assert(oai.Paths["/index"].Put.RequestBody.Value.Content["application/json"].Schema.Ref, `github.com.gogf.gf.v2.protocol.goai_test.Req`)
t.Assert(len(oai.Paths["/index"].Put.Responses["200"].Value.Content["application/json"].Schema.Value.Properties), 3)
t.Assert(len(oai.Paths["/index"].Put.Responses["200"].Value.Content["application/json"].Schema.Value.Properties.Map()), 3)
})
}
@ -607,10 +607,10 @@ func TestOpenApiV3_CommonResponse_SubDataField(t *testing.T) {
t.AssertNil(err)
// Schema asserts.
// fmt.Println(oai.String())
t.Assert(len(oai.Components.Schemas), 4)
t.Assert(len(oai.Components.Schemas.Map()), 4)
t.Assert(len(oai.Paths), 1)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties), 1)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties[`Response`].Value.Properties), 7)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties.Map()), 1)
t.Assert(len(oai.Paths["/index"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties.Get(`Response`).Value.Properties.Map()), 7)
})
}
@ -663,12 +663,12 @@ func TestOpenApiV3_ShortTags(t *testing.T) {
t.AssertNil(err)
// fmt.Println(oai.String())
// Schema asserts.
t.Assert(len(oai.Components.Schemas), 3)
t.Assert(len(oai.Components.Schemas.Map()), 3)
t.Assert(oai.Paths[`/test1/{appId}`].Summary, `CreateResourceReq sum`)
t.Assert(oai.
Components.
Schemas[`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`].
Value.Properties[`resourceId`].Value.Description, `资源Id`)
Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.CreateResourceReq`).
Value.Properties.Get(`resourceId`).Value.Description, `资源Id`)
})
}
@ -698,7 +698,7 @@ func TestOpenApiV3_HtmlResponse(t *testing.T) {
t.AssertNil(err)
// fmt.Println(oai.String())
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.Res`].Value.Type, goai.TypeString)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.Res`).Value.Type, goai.TypeString)
})
}
@ -745,6 +745,6 @@ func TestOpenApiV3_HtmlResponseWithCommonResponse(t *testing.T) {
t.AssertNil(err)
// fmt.Println(oai.String())
t.Assert(oai.Components.Schemas[`github.com.gogf.gf.v2.protocol.goai_test.Res`].Value.Type, goai.TypeString)
t.Assert(oai.Components.Schemas.Get(`github.com.gogf.gf.v2.protocol.goai_test.Res`).Value.Type, goai.TypeString)
})
}