You can use the reflect package from the standard library to inspect the struct and its tags and you can use the gopkg.in/yaml.v3 package to generate the Open API format. You just need to write the logic that translates your type into another, one that matches the structure of the Open API document.
Here's an example of how you could approach this, note that it is incomplete and should therefore not be used as is:
// declare a structure that matches the OpenAPI's yaml document
type DataType struct {
Type string `yaml:"type,omitempty"`
Props map[string]*DataType `yaml:"properties,omitempty"`
XML *XML `yaml:"xml,omitempty"`
}
type XML struct {
Name string `yaml:"name,omitempty"`
Attr bool `yaml:"attribute,omitempty"`
}
// write a marshal func that converts a given type to the structure declared above
// - this example converts only plain structs
func marshalOpenAPI(v interface{}) (interface{}, error) {
rt := reflect.TypeOf(v)
if rt.Kind() == reflect.Struct {
obj := DataType{Type: "object"}
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i)
tag := strings.Split(f.Tag.Get("xml"), ",")
if len(tag) == 0 || len(tag[0]) == 0 { // no name?
continue
}
if obj.Props == nil {
obj.Props = make(map[string]*DataType)
}
name := tag[0]
obj.Props[name] = &DataType{
Type: goTypeToOpenAPIType(f.Type),
}
if len(tag) > 1 && tag[1] == "attr" {
obj.Props[name].XML = &XML{Attr: true}
}
}
return obj, nil
}
return nil, fmt.Errorf("unsupported type")
}
// have all your types implement the yaml.Marshaler interface by
// delegating to the marshal func implemented above
func (e Error) MarshalYAML() (interface{}, error) {
return marshalOpenAPI(e)
}
// marshal the types
yaml.Marshal(map[string]map[string]interface{}{
"schemas": {
"error": Error{},
// ...
},
})
Try it on playground.