This package can be used to generate Avro Schemas from Go types through reflection.
The following Go type:
type Entity struct {
AStrField *string `json:"a_str_field"`
AIntField *int `json:"a_int_field"`
ABoolField *bool `json:"a_bool_field"`
AFloatField *float32 `json:"a_float_field"`
ADoubleField *float64 `json:"a_double_field"`
}
Results in following JSON Schema:
import "github.com/wirelessr/avroschema"
avroschema.Reflect(&Entity{})
{
"name": "Entity",
"type": "record",
"fields": [
{ "name": "a_str_field", "type": "string" },
{ "name": "a_int_field", "type": "int" },
{ "name": "a_bool_field", "type": "boolean" },
{ "name": "a_float_field", "type": "float" },
{ "name": "a_double_field", "type": "double" }
]
}
The Reflector
struct provides several configuration options:
reflector := &avroschema.Reflector{
BeBackwardTransitive: true, // Make all fields optional
EmitAllFields: true, // Include fields without tags
SkipTagFieldNames: false, // Use JSON/BSON tag names
Mapper: nil, // Custom type mapper
NameMapping: nil, // Custom name mapping
Namespace: "", // Schema namespace
}
The package supports nested structs and arrays:
type Address struct {
Street string `json:"street"`
City string `json:"city"`
}
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
Emails []string `json:"emails"`
}
Resulting schema:
{
"name": "Person",
"type": "record",
"fields": [
{ "name": "name", "type": "string" },
{ "name": "age", "type": "int" },
{
"name": "address",
"type": {
"name": "Address",
"type": "record",
"fields": [
{ "name": "street", "type": "string" },
{ "name": "city", "type": "string" }
]
}
},
{ "name": "emails", "type": { "type": "array", "items": "string" } }
]
}
Time values are automatically converted to timestamp-millis:
type Event struct {
ID string `json:"id"`
Timestamp time.Time `json:"timestamp"`
}
{
"name": "Event",
"type": "record",
"fields": [
{ "name": "id", "type": "string" },
{ "name": "timestamp", "type": "long", "logicalType": "timestamp-millis" }
]
}
You can implement custom type mapping:
reflector.Mapper = func(t reflect.Type) any {
if t == reflect.TypeOf(primitive.ObjectID{}) {
return "string"
}
return nil // fall back to default mapping
}
Mark fields as optional with ,omitempty
:
type User struct {
Username string `json:"username"`
Email *string `json:"email,omitempty"`
}
{
"name": "User",
"type": "record",
"fields": [
{ "name": "username", "type": "string" },
{ "name": "email", "type": ["null", "string"] }
]
}
The popular MongoDB ORM, mgm, is supported:
The following Go type:
type Book struct {
mgm.DefaultModel `bson:",inline"`
Name string `json:"name" bson:"name"`
Pages int `json:"pages" bson:"pages"`
ObjId primitive.ObjectID `json:"obj_id" bson:"obj_id"`
ArrivedAt primitive.DateTime `json:"arrived_at" bson:"arrived_at"`
RefData bson.M `json:"ref_data" bson:"ref_data"`
Author []string `json:"author" bson:"author"`
}
The type mappings can be customized by Mapper
.
import (
"github.com/wirelessr/avroschema"
"github.com/wirelessr/avroschema/mongo"
)
reflector := new(avroschema.Reflector)
reflector.Mapper = MgmExtension
reflector.Reflect(&Book{})
Results in following JSON Schema:
{
"name": "Book",
"type": "record",
"fields": [
{ "name": "_id", "type": "string" },
{ "name": "created_at", "type": "long", "logicalType": "timestamp-millis" },
{ "name": "updated_at", "type": "long", "logicalType": "timestamp-millis" },
{ "name": "name", "type": "string" },
{ "name": "pages", "type": "int" },
{ "name": "obj_id", "type": "string" },
{ "name": "arrived_at", "type": "long", "logicalType": "timestamp-millis" },
{ "name": "ref_data", "type": "string" },
{ "name": "author", "type": "array", "items": "string" }
]
}