Skip to content

Commit 9e800e8

Browse files
committed
Always use SetSchema if type implements SetSchemar interface.
1 parent 783206b commit 9e800e8

File tree

1 file changed

+149
-144
lines changed

1 file changed

+149
-144
lines changed

openapi3gen/openapi3gen.go

Lines changed: 149 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -235,175 +235,180 @@ func (g *Generator) generateWithoutSaving(parents []*theTypeInfo, t reflect.Type
235235
schema := &openapi3.Schema{}
236236
schema.Nullable = isNullable
237237

238-
switch t.Kind() {
239-
case reflect.Func, reflect.Chan:
240-
return nil, nil // ignore
241-
242-
case reflect.Bool:
243-
schema.Type = &openapi3.Types{"boolean"}
244-
245-
case reflect.Int:
246-
schema.Type = &openapi3.Types{"integer"}
247-
case reflect.Int8:
248-
schema.Type = &openapi3.Types{"integer"}
249-
schema.Min = &minInt8
250-
schema.Max = &maxInt8
251-
case reflect.Int16:
252-
schema.Type = &openapi3.Types{"integer"}
253-
schema.Min = &minInt16
254-
schema.Max = &maxInt16
255-
case reflect.Int32:
256-
schema.Type = &openapi3.Types{"integer"}
257-
schema.Format = "int32"
258-
case reflect.Int64:
259-
schema.Type = &openapi3.Types{"integer"}
260-
schema.Format = "int64"
261-
case reflect.Uint:
262-
schema.Type = &openapi3.Types{"integer"}
263-
schema.Min = &zeroInt
264-
case reflect.Uint8:
265-
schema.Type = &openapi3.Types{"integer"}
266-
schema.Min = &zeroInt
267-
schema.Max = &maxUint8
268-
case reflect.Uint16:
269-
schema.Type = &openapi3.Types{"integer"}
270-
schema.Min = &zeroInt
271-
schema.Max = &maxUint16
272-
case reflect.Uint32:
273-
schema.Type = &openapi3.Types{"integer"}
274-
schema.Min = &zeroInt
275-
schema.Max = &maxUint32
276-
case reflect.Uint64:
277-
schema.Type = &openapi3.Types{"integer"}
278-
schema.Min = &zeroInt
279-
schema.Max = &maxUint64
280-
281-
case reflect.Float32:
282-
schema.Type = &openapi3.Types{"number"}
283-
schema.Format = "float"
284-
case reflect.Float64:
285-
schema.Type = &openapi3.Types{"number"}
286-
schema.Format = "double"
287-
288-
case reflect.String:
289-
schema.Type = &openapi3.Types{"string"}
238+
// Object has their own schema's implementation, so we'll use those
239+
var setSchemar SetSchemar
240+
if v := reflect.New(t); v.CanInterface() {
241+
if v, ok := v.Interface().(SetSchemar); ok {
242+
setSchemar = v
243+
}
244+
}
290245

291-
case reflect.Slice:
292-
if t.Elem().Kind() == reflect.Uint8 {
293-
if t != rawMessageType {
294-
schema.Type = &openapi3.Types{"string"}
295-
schema.Format = "byte"
246+
if setSchemar != nil {
247+
setSchemar.SetSchema(schema)
248+
} else {
249+
250+
switch t.Kind() {
251+
case reflect.Func, reflect.Chan:
252+
return nil, nil // ignore
253+
254+
case reflect.Bool:
255+
schema.Type = &openapi3.Types{"boolean"}
256+
257+
case reflect.Int:
258+
schema.Type = &openapi3.Types{"integer"}
259+
case reflect.Int8:
260+
schema.Type = &openapi3.Types{"integer"}
261+
schema.Min = &minInt8
262+
schema.Max = &maxInt8
263+
case reflect.Int16:
264+
schema.Type = &openapi3.Types{"integer"}
265+
schema.Min = &minInt16
266+
schema.Max = &maxInt16
267+
case reflect.Int32:
268+
schema.Type = &openapi3.Types{"integer"}
269+
schema.Format = "int32"
270+
case reflect.Int64:
271+
schema.Type = &openapi3.Types{"integer"}
272+
schema.Format = "int64"
273+
case reflect.Uint:
274+
schema.Type = &openapi3.Types{"integer"}
275+
schema.Min = &zeroInt
276+
case reflect.Uint8:
277+
schema.Type = &openapi3.Types{"integer"}
278+
schema.Min = &zeroInt
279+
schema.Max = &maxUint8
280+
case reflect.Uint16:
281+
schema.Type = &openapi3.Types{"integer"}
282+
schema.Min = &zeroInt
283+
schema.Max = &maxUint16
284+
case reflect.Uint32:
285+
schema.Type = &openapi3.Types{"integer"}
286+
schema.Min = &zeroInt
287+
schema.Max = &maxUint32
288+
case reflect.Uint64:
289+
schema.Type = &openapi3.Types{"integer"}
290+
schema.Min = &zeroInt
291+
schema.Max = &maxUint64
292+
293+
case reflect.Float32:
294+
schema.Type = &openapi3.Types{"number"}
295+
schema.Format = "float"
296+
case reflect.Float64:
297+
schema.Type = &openapi3.Types{"number"}
298+
schema.Format = "double"
299+
300+
case reflect.String:
301+
schema.Type = &openapi3.Types{"string"}
302+
303+
case reflect.Slice:
304+
if t.Elem().Kind() == reflect.Uint8 {
305+
if t != rawMessageType {
306+
schema.Type = &openapi3.Types{"string"}
307+
schema.Format = "byte"
308+
}
309+
} else {
310+
schema.Type = &openapi3.Types{"array"}
311+
items, err := g.generateSchemaRefFor(parents, t.Elem(), name, tag)
312+
if err != nil {
313+
if _, ok := err.(*CycleError); ok && !g.opts.throwErrorOnCycle {
314+
items = g.generateCycleSchemaRef(t.Elem(), schema)
315+
} else {
316+
return nil, err
317+
}
318+
}
319+
if items != nil {
320+
g.SchemaRefs[items]++
321+
schema.Items = items
322+
}
296323
}
297-
} else {
298-
schema.Type = &openapi3.Types{"array"}
299-
items, err := g.generateSchemaRefFor(parents, t.Elem(), name, tag)
324+
325+
case reflect.Map:
326+
schema.Type = &openapi3.Types{"object"}
327+
additionalProperties, err := g.generateSchemaRefFor(parents, t.Elem(), name, tag)
300328
if err != nil {
301329
if _, ok := err.(*CycleError); ok && !g.opts.throwErrorOnCycle {
302-
items = g.generateCycleSchemaRef(t.Elem(), schema)
330+
additionalProperties = g.generateCycleSchemaRef(t.Elem(), schema)
303331
} else {
304332
return nil, err
305333
}
306334
}
307-
if items != nil {
308-
g.SchemaRefs[items]++
309-
schema.Items = items
335+
if additionalProperties != nil {
336+
g.SchemaRefs[additionalProperties]++
337+
schema.AdditionalProperties = openapi3.AdditionalProperties{Schema: additionalProperties}
310338
}
311-
}
312339

313-
case reflect.Map:
314-
schema.Type = &openapi3.Types{"object"}
315-
additionalProperties, err := g.generateSchemaRefFor(parents, t.Elem(), name, tag)
316-
if err != nil {
317-
if _, ok := err.(*CycleError); ok && !g.opts.throwErrorOnCycle {
318-
additionalProperties = g.generateCycleSchemaRef(t.Elem(), schema)
340+
case reflect.Struct:
341+
if t == timeType {
342+
schema.Type = &openapi3.Types{"string"}
343+
schema.Format = "date-time"
319344
} else {
320-
return nil, err
321-
}
322-
}
323-
if additionalProperties != nil {
324-
g.SchemaRefs[additionalProperties]++
325-
schema.AdditionalProperties = openapi3.AdditionalProperties{Schema: additionalProperties}
326-
}
327-
328-
case reflect.Struct:
329-
if t == timeType {
330-
schema.Type = &openapi3.Types{"string"}
331-
schema.Format = "date-time"
332-
} else {
333-
typeName := g.generateTypeName(t)
334-
335-
if _, ok := g.componentSchemaRefs[typeName]; ok && g.opts.exportComponentSchemas.ExportComponentSchemas {
336-
// Check if we have already parsed this component schema ref based on the name of the struct
337-
// and use that if so
338-
return openapi3.NewSchemaRef(fmt.Sprintf("#/components/schemas/%s", typeName), schema), nil
339-
}
345+
typeName := g.generateTypeName(t)
340346

341-
for _, fieldInfo := range typeInfo.Fields {
342-
// Only fields with JSON tag are considered (by default)
343-
if !fieldInfo.HasJSONTag && !g.opts.useAllExportedFields {
344-
continue
347+
if _, ok := g.componentSchemaRefs[typeName]; ok && g.opts.exportComponentSchemas.ExportComponentSchemas {
348+
// Check if we have already parsed this component schema ref based on the name of the struct
349+
// and use that if so
350+
return openapi3.NewSchemaRef(fmt.Sprintf("#/components/schemas/%s", typeName), schema), nil
345351
}
346-
// If asked, try to use yaml tag
347-
fieldName, fType := fieldInfo.JSONName, fieldInfo.Type
348-
if !fieldInfo.HasJSONTag && g.opts.useAllExportedFields {
349-
// Handle anonymous fields/embedded structs
350-
if t.Field(fieldInfo.Index[0]).Anonymous {
351-
ref, err := g.generateSchemaRefFor(parents, fType, fieldName, tag)
352-
if err != nil {
353-
if _, ok := err.(*CycleError); ok && !g.opts.throwErrorOnCycle {
354-
ref = g.generateCycleSchemaRef(fType, schema)
355-
} else {
356-
return nil, err
352+
353+
for _, fieldInfo := range typeInfo.Fields {
354+
// Only fields with JSON tag are considered (by default)
355+
if !fieldInfo.HasJSONTag && !g.opts.useAllExportedFields {
356+
continue
357+
}
358+
// If asked, try to use yaml tag
359+
fieldName, fType := fieldInfo.JSONName, fieldInfo.Type
360+
if !fieldInfo.HasJSONTag && g.opts.useAllExportedFields {
361+
// Handle anonymous fields/embedded structs
362+
if t.Field(fieldInfo.Index[0]).Anonymous {
363+
ref, err := g.generateSchemaRefFor(parents, fType, fieldName, tag)
364+
if err != nil {
365+
if _, ok := err.(*CycleError); ok && !g.opts.throwErrorOnCycle {
366+
ref = g.generateCycleSchemaRef(fType, schema)
367+
} else {
368+
return nil, err
369+
}
370+
}
371+
if ref != nil {
372+
g.SchemaRefs[ref]++
373+
schema.WithPropertyRef(fieldName, ref)
374+
}
375+
} else {
376+
ff := getStructField(t, fieldInfo)
377+
if tag, ok := ff.Tag.Lookup("yaml"); ok && tag != "-" {
378+
fieldName, fType = tag, ff.Type
357379
}
358380
}
359-
if ref != nil {
360-
g.SchemaRefs[ref]++
361-
schema.WithPropertyRef(fieldName, ref)
362-
}
363-
} else {
381+
}
382+
383+
// extract the field tag if we have a customizer
384+
var fieldTag reflect.StructTag
385+
if g.opts.schemaCustomizer != nil {
364386
ff := getStructField(t, fieldInfo)
365-
if tag, ok := ff.Tag.Lookup("yaml"); ok && tag != "-" {
366-
fieldName, fType = tag, ff.Type
387+
fieldTag = ff.Tag
388+
}
389+
390+
ref, err := g.generateSchemaRefFor(parents, fType, fieldName, fieldTag)
391+
if err != nil {
392+
if _, ok := err.(*CycleError); ok && !g.opts.throwErrorOnCycle {
393+
ref = g.generateCycleSchemaRef(fType, schema)
394+
} else {
395+
return nil, err
367396
}
368397
}
369-
}
398+
if ref != nil {
399+
g.SchemaRefs[ref]++
400+
schema.WithPropertyRef(fieldName, ref)
401+
}
370402

371-
// extract the field tag if we have a customizer
372-
var fieldTag reflect.StructTag
373-
if g.opts.schemaCustomizer != nil {
374-
ff := getStructField(t, fieldInfo)
375-
fieldTag = ff.Tag
376403
}
377404

378-
ref, err := g.generateSchemaRefFor(parents, fType, fieldName, fieldTag)
379-
if err != nil {
380-
if _, ok := err.(*CycleError); ok && !g.opts.throwErrorOnCycle {
381-
ref = g.generateCycleSchemaRef(fType, schema)
382-
} else {
383-
return nil, err
384-
}
385-
}
386-
if ref != nil {
387-
g.SchemaRefs[ref]++
388-
schema.WithPropertyRef(fieldName, ref)
405+
// Object only if it has properties
406+
if schema.Properties != nil {
407+
schema.Type = &openapi3.Types{"object"}
389408
}
390-
391409
}
392410

393-
// Object only if it has properties
394-
if schema.Properties != nil {
395-
schema.Type = &openapi3.Types{"object"}
396-
}
397411
}
398-
399-
default:
400-
// Object has their own schema's implementation, so we'll use those
401-
if v := reflect.New(t); v.CanInterface() {
402-
if v, ok := v.Interface().(SetSchemar); ok {
403-
v.SetSchema(schema)
404-
}
405-
}
406-
407412
}
408413

409414
if g.opts.schemaCustomizer != nil {

0 commit comments

Comments
 (0)