Skip to content

Commit

Permalink
Merge pull request #330 from lsdch/main
Browse files Browse the repository at this point in the history
Allow specifying type aliases to provide schema definitions
  • Loading branch information
danielgtaylor committed Mar 25, 2024
2 parents 7b6dc40 + 3b9f6e7 commit 38cf30c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
14 changes: 14 additions & 0 deletions registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Registry interface {
SchemaFromRef(ref string) *Schema
TypeFromRef(ref string) reflect.Type
Map() map[string]*Schema
RegisterTypeAlias(t reflect.Type, alias reflect.Type)
}

// DefaultSchemaNamer provides schema names for types. It uses the type name
Expand Down Expand Up @@ -62,10 +63,17 @@ type mapRegistry struct {
types map[string]reflect.Type
seen map[reflect.Type]bool
namer func(reflect.Type, string) string
aliases map[reflect.Type]reflect.Type
}

func (r *mapRegistry) Schema(t reflect.Type, allowRef bool, hint string) *Schema {
t = deref(t)

alias, ok := r.aliases[t]
if ok {
return r.Schema(alias, allowRef, hint)
}

getsRef := t.Kind() == reflect.Struct
if t == timeType {
// Special case: time.Time is always a string.
Expand Down Expand Up @@ -134,6 +142,11 @@ func (r *mapRegistry) MarshalYAML() (interface{}, error) {
return r.schemas, nil
}

// RegisterTypeAlias(t, alias) makes the schema generator use the `alias` type instead of `t`.
func (r *mapRegistry) RegisterTypeAlias(t reflect.Type, alias reflect.Type) {
r.aliases[t] = alias
}

// NewMapRegistry creates a new registry that stores schemas in a map and
// returns references to them using the given prefix.
func NewMapRegistry(prefix string, namer func(t reflect.Type, hint string) string) Registry {
Expand All @@ -142,6 +155,7 @@ func NewMapRegistry(prefix string, namer func(t reflect.Type, hint string) strin
schemas: map[string]*Schema{},
types: map[string]reflect.Type{},
seen: map[reflect.Type]bool{},
aliases: map[reflect.Type]reflect.Type{},
namer: namer,
}
}
17 changes: 17 additions & 0 deletions registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,20 @@ func TestDefaultSchemaNamer(t *testing.T) {
})
}
}

func TestSchemaAlias(t *testing.T) {
type StringContainer struct {
Value string
}
type StructWithStringContainer struct {
Name StringContainer `json:"name,omitempty"`
}
type StructWithString struct {
Name string `json:"name,omitempty"`
}
registry := NewMapRegistry("#/components/schemas", DefaultSchemaNamer)
registry.RegisterTypeAlias(reflect.TypeOf(StringContainer{}), reflect.TypeOf(""))
schemaWithContainer := registry.Schema(reflect.TypeOf(StructWithStringContainer{}), false, "")
schemaWithString := registry.Schema(reflect.TypeOf(StructWithString{}), false, "")
assert.Equal(t, schemaWithString, schemaWithContainer)
}

0 comments on commit 38cf30c

Please sign in to comment.