diff --git a/openapi/generator.go b/openapi/generator.go index 99f6833..74f19ee 100644 --- a/openapi/generator.go +++ b/openapi/generator.go @@ -458,6 +458,14 @@ func (g *Generator) setOperationParams(op *Operation, t, parent reflect.Type, al } sch := op.RequestBody.Content[mt].Schema if sch != nil { + // Get description + if t.Implements(tofDescriptor) { + i, ok := reflect.New(t).Interface().(Descriptor) + if ok { + sch.Schema.Description = i.Description() + } + } + name := strings.Title(op.ID) + "Input" g.api.Components.Schemas[name] = sch op.RequestBody.Content[mt].Schema = &SchemaOrRef{Reference: &Reference{ diff --git a/openapi/generator_test.go b/openapi/generator_test.go index e63ac74..ddb1aa2 100644 --- a/openapi/generator_test.go +++ b/openapi/generator_test.go @@ -452,35 +452,41 @@ func diffJSON(a, b []byte) (bool, error) { return reflect.DeepEqual(j2, j), nil } +type InEmbed struct { + D int `query:"xd" enum:"1,2,3" default:"1"` + E bool `query:"e"` + F *string `json:"f" description:"This is F"` + G []byte `validate:"required"` + H uint16 `binding:"-"` + K []string `query:"k" enum:"aaa,bbb,ccc"` +} +type inEmbedPrivate struct { + I string `query:"i"` +} +type h string +type In struct { + *In // ignored, recusrive embedding + *InEmbed + *inEmbedPrivate + + A int `path:"a" description:"This is A" deprecated:"oui"` + B time.Time `query:"b" validate:"required" description:"This is B"` + C string `header:"X-Test-C" description:"This is C" default:"test"` + d int // ignored, unexported field + E int `path:"a"` // ignored, duplicate of A + F *string `json:"f"` // ignored, duplicate of F in InEmbed + G *inEmbedPrivate + h // ignored, embedded field of non-struct type + +} + +func (i In) Description() string { + return "Test input schema description" +} + // TestAddOperation tests that an operation can be added // and generates the according specification. func TestAddOperation(t *testing.T) { - type InEmbed struct { - D int `query:"xd" enum:"1,2,3" default:"1"` - E bool `query:"e"` - F *string `json:"f" description:"This is F"` - G []byte `validate:"required"` - H uint16 `binding:"-"` - K []string `query:"k" enum:"aaa,bbb,ccc"` - } - type inEmbedPrivate struct { - I string `query:"i"` - } - type h string - type In struct { - *In // ignored, recusrive embedding - *InEmbed - *inEmbedPrivate - - A int `path:"a" description:"This is A" deprecated:"oui"` - B time.Time `query:"b" validate:"required" description:"This is B"` - C string `header:"X-Test-C" description:"This is C" default:"test"` - d int // ignored, unexported field - E int `path:"a"` // ignored, duplicate of A - F *string `json:"f"` // ignored, duplicate of F in InEmbed - G *inEmbedPrivate - h // ignored, embedded field of non-struct type - } type CustomError struct{} var Header string @@ -524,6 +530,17 @@ func TestAddOperation(t *testing.T) { if err != nil { t.Error(err) } + + requestBodyName := infos.ID + "Input" + requestBody, ok := g.API().Components.Schemas[requestBodyName] + if !ok { + t.Errorf("expected to found item for schema %s", requestBodyName) + } + + if requestBody.Schema.Description == "" { + t.Errorf("expected to found description for schema %s", requestBodyName) + } + // Add another operation with no input/output type. // No parameters should be present, and a response // matching the default status code used by tonic diff --git a/openapi/types.go b/openapi/types.go index cd3fd59..f519115 100644 --- a/openapi/types.go +++ b/openapi/types.go @@ -12,8 +12,9 @@ import ( ) var ( - tofDataType = reflect.TypeOf((*DataType)(nil)).Elem() - tofNullable = reflect.TypeOf((*Nullable)(nil)).Elem() + tofDataType = reflect.TypeOf((*DataType)(nil)).Elem() + tofNullable = reflect.TypeOf((*Nullable)(nil)).Elem() + tofDescriptor = reflect.TypeOf((*Descriptor)(nil)).Elem() // Native. tofTime = reflect.TypeOf(time.Time{}) @@ -49,6 +50,12 @@ type Exampler interface { ParseExample(v string) (interface{}, error) } +// Descriptor is the interface implemented by the RequestBody input schema +// that provides a description for this schema kind +type Descriptor interface { + Description() string +} + // Nullable is the interface implemented by the types // that can be nullable. type Nullable interface {