improve package goai; add example for array items response definition

This commit is contained in:
John Guo
2022-02-16 15:28:40 +08:00
parent 77fc8866bf
commit 6d09328d6d
5 changed files with 90 additions and 20 deletions

View File

@ -0,0 +1,33 @@
package main
import (
"context"
"github.com/gogf/gf/v2/frame/g"
)
type Req struct {
g.Meta `path:"/user" method:"get"`
}
type Res []Item
type Item struct {
Id int64
Name string
}
var (
User = cUser{}
)
type cUser struct{}
func (c *cUser) GetList(ctx context.Context, req *Req) (res *Res, err error) {
res = &Res{
{Id: 1, Name: "john"},
{Id: 2, Name: "smith"},
{Id: 3, Name: "alice"},
{Id: 4, Name: "katyusha"},
}
return
}

View File

@ -0,0 +1,23 @@
package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
func main() {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind(
User,
)
})
oai := s.GetOpenApi()
oai.Config.CommonResponse = ghttp.DefaultHandlerResponse{}
oai.Config.CommonResponseDataField = "Data"
s.SetOpenApiPath("/api")
s.SetSwaggerPath("/swagger")
s.SetPort(8199)
s.Run()
}

View File

@ -213,9 +213,9 @@ func (oai *OpenApiV3) addPath(in addPathInput) error {
contentTypes = oai.Config.ReadContentTypes
tagMimeValue = gmeta.Get(outputObject.Interface(), TagNameMime).String()
refInput = getResponseSchemaRefInput{
BusinessStructName: outputStructTypeName,
ResponseObject: oai.Config.CommonResponse,
ResponseDataField: oai.Config.CommonResponseDataField,
BusinessStructName: outputStructTypeName,
CommonResponseObject: oai.Config.CommonResponse,
CommonResponseDataField: oai.Config.CommonResponseDataField,
}
)
if tagMimeValue != "" {
@ -224,8 +224,8 @@ func (oai *OpenApiV3) addPath(in addPathInput) error {
for _, v := range contentTypes {
// If customized response mime type, it then ignores common response feature.
if tagMimeValue != "" {
refInput.ResponseObject = nil
refInput.ResponseDataField = ""
refInput.CommonResponseObject = nil
refInput.CommonResponseDataField = ""
}
schemaRef, err := oai.getResponseSchemaRef(refInput)
if err != nil {

View File

@ -38,33 +38,33 @@ func (r ResponseRef) MarshalJSON() ([]byte, error) {
}
type getResponseSchemaRefInput struct {
BusinessStructName string // The business struct name.
ResponseObject interface{} // Common response object.
ResponseDataField string // Common response data field.
BusinessStructName string // The business struct name.
CommonResponseObject interface{} // Common response object.
CommonResponseDataField string // Common response data field.
}
func (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*SchemaRef, error) {
if in.ResponseObject == nil {
if in.CommonResponseObject == nil {
return &SchemaRef{
Ref: in.BusinessStructName,
}, nil
}
var (
dataFieldsPartsArray = gstr.Split(in.ResponseDataField, ".")
dataFieldsPartsArray = gstr.Split(in.CommonResponseDataField, ".")
bizResponseStructSchemaRef, bizResponseStructSchemaRefExist = oai.Components.Schemas[in.BusinessStructName]
schema, err = oai.structToSchema(in.ResponseObject)
schema, err = oai.structToSchema(in.CommonResponseObject)
)
if err != nil {
return nil, err
}
if in.ResponseDataField == "" && bizResponseStructSchemaRefExist {
if in.CommonResponseDataField == "" && bizResponseStructSchemaRefExist {
for k, v := range bizResponseStructSchemaRef.Value.Properties {
schema.Properties[k] = v
}
} else {
structFields, _ := gstructs.Fields(gstructs.FieldsInput{
Pointer: in.ResponseObject,
Pointer: in.CommonResponseObject,
RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
})
for _, structField := range structFields {
@ -86,9 +86,9 @@ func (oai *OpenApiV3) getResponseSchemaRef(in getResponseSchemaRefInput) (*Schem
structFieldInstance = reflect.New(structField.Type().Type).Elem()
)
schemaRef, err := oai.getResponseSchemaRef(getResponseSchemaRefInput{
BusinessStructName: in.BusinessStructName,
ResponseObject: structFieldInstance,
ResponseDataField: gstr.Join(dataFieldsPartsArray[1:], "."),
BusinessStructName: in.BusinessStructName,
CommonResponseObject: structFieldInstance,
CommonResponseDataField: gstr.Join(dataFieldsPartsArray[1:], "."),
})
if err != nil {
return nil, err

View File

@ -10,6 +10,7 @@ import (
"reflect"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/os/gstructs"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
@ -64,6 +65,8 @@ type Discriminator struct {
Mapping map[string]string `json:"mapping,omitempty" yaml:"mapping,omitempty"`
}
// addSchema creates schemas with objects.
// Note that the `object` can be array alias like: `type Res []Item`.
func (oai *OpenApiV3) addSchema(object ...interface{}) error {
for _, v := range object {
if err := oai.doAddSchemaSingle(v); err != nil {
@ -104,10 +107,6 @@ func (oai *OpenApiV3) doAddSchemaSingle(object interface{}) error {
// structToSchema converts and returns given struct object as Schema.
func (oai *OpenApiV3) structToSchema(object interface{}) (*Schema, error) {
structFields, _ := gstructs.Fields(gstructs.FieldsInput{
Pointer: object,
RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
})
var (
tagMap = gmeta.Data(object)
schema = &Schema{
@ -123,6 +122,21 @@ func (oai *OpenApiV3) structToSchema(object interface{}) (*Schema, error) {
if schema.Type != "" && schema.Type != TypeObject {
return schema, nil
}
// []struct.
if utils.IsArray(object) {
schema.Type = TypeArray
subSchemaRef, err := oai.newSchemaRefWithGolangType(reflect.TypeOf(object).Elem(), nil)
if err != nil {
return nil, err
}
schema.Items = subSchemaRef
return schema, nil
}
// struct.
structFields, _ := gstructs.Fields(gstructs.FieldsInput{
Pointer: object,
RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
})
schema.Type = TypeObject
for _, structField := range structFields {
if !gstr.IsLetterUpper(structField.Name()[0]) {