diff --git a/openapi/schema.go b/openapi/schema.go index 001afafb..54d28a9d 100644 --- a/openapi/schema.go +++ b/openapi/schema.go @@ -65,7 +65,7 @@ type Schema struct { type properties = orderedmap.OrderedMap[string, *renderer[schemaRenderer]] type schemaRenderer struct { - Type string `json:"type" yaml:"type"` + Type string `json:"type,omitempty" yaml:"type,omitempty"` // AnyOf 等不为空,此值可为空 XML *XML `json:"xml,omitempty" yaml:"xml,omitempty"` ExternalDocs *externalDocsRenderer `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` Title string `json:"title,omitempty" yaml:"title,omitempty"` @@ -93,6 +93,50 @@ func NewSchema(v any, title, desc web.LocaleStringer) *Schema { return newSchema(nil, v, title, desc) } +func AnyOfSchema(title, desc web.LocaleStringer, v ...any) *Schema { + return xOfSchema(0, title, desc, v...) +} + +func OneOfSchema(title, desc web.LocaleStringer, v ...any) *Schema { + return xOfSchema(1, title, desc, v...) +} + +func AllOfSchema(title, desc web.LocaleStringer, v ...any) *Schema { + return xOfSchema(2, title, desc, v...) +} + +// - 0 anyof +// - 1 oneof +// - 2 allof +func xOfSchema(typ int, title, desc web.LocaleStringer, v ...any) *Schema { + if len(v) == 0 { + panic("参数 v 必不可少") + } + + of := make([]*Schema, 0, len(v)) + for _, vv := range v { + of = append(of, NewSchema(vv, nil, nil)) + } + + s := &Schema{ + Title: title, + Description: desc, + } + + switch typ { + case 0: + s.AnyOf = of + case 1: + s.OneOf = of + case 2: + s.AllOf = of + default: + panic("无效的参数 typ") + } + + return s +} + func newSchema(d *Document, v any, title, desc web.LocaleStringer) *Schema { s := &Schema{ Title: title, diff --git a/openapi/schema_test.go b/openapi/schema_test.go index e0e5af00..38954d02 100644 --- a/openapi/schema_test.go +++ b/openapi/schema_test.go @@ -26,6 +26,35 @@ type schemaObject2 struct { schemaObject1 } +func TestOfSchema(t *testing.T) { + a := assert.New(t, false) + + a.PanicString(func() { + AllOfSchema(nil, nil) + }, "参数 v 必不可少") + + s := AnyOfSchema(web.Phrase("lang"), nil, "1", 0) + a.Length(s.AnyOf, 2). + Empty(s.Type). + Equal(s.AnyOf[0].Type, TypeString). + Equal(s.AnyOf[0].Default, "1"). + Equal(s.AnyOf[1].Type, TypeInteger). + Nil(s.AnyOf[1].Default) + + s = OneOfSchema(web.Phrase("lang"), nil, true, uint(2)) + a.Length(s.OneOf, 2). + Empty(s.Type). + Equal(s.OneOf[0].Type, TypeBoolean). + Equal(s.OneOf[0].Default, true). + Equal(s.OneOf[1].Type, TypeInteger) + + s = AllOfSchema(web.Phrase("lang"), nil, "1", 2) + a.Length(s.AllOf, 2). + Empty(s.Type). + Equal(s.AllOf[0].Type, TypeString). + Equal(s.AllOf[1].Type, TypeInteger) +} + func TestDocument_newSchema(t *testing.T) { a := assert.New(t, false) ss := newServer(a) diff --git a/openapi/valid.go b/openapi/valid.go index c815c49d..2a8edf85 100644 --- a/openapi/valid.go +++ b/openapi/valid.go @@ -112,7 +112,7 @@ func (s *Schema) valid(skipRefNotNil bool) *web.FieldError { return nil } - if s.Type == "" { + if s.Type == "" && len(s.AnyOf) == 0 && len(s.AllOf) == 0 && len(s.OneOf) == 0 { return web.NewFieldError("Type", "不能为空") }