go.md

August 3, 2026 ยท View on GitHub

Output Layout

Go output path depends on schema options and --go_out.

For addressbook.fdl, go_package is configured and generated output follows the configured import path/package (for example under your --go_out root).

Without go_package, output uses the requested --go_out directory and package-derived file naming.

Type Generation

Nested types use underscore naming by default (Person_PhoneType, Person_PhoneNumber):

type Person_PhoneType int32

const (
    Person_PhoneTypeMobile Person_PhoneType = 0
    Person_PhoneTypeHome   Person_PhoneType = 1
    Person_PhoneTypeWork   Person_PhoneType = 2
)

type Person_PhoneNumber struct {
    Number    string           `fory:"id=1"`
    PhoneType Person_PhoneType `fory:"id=2"`
}

Messages generate structs with fory tags and byte helpers:

type Person struct {
    Name   string               `fory:"id=1"`
    Id     int32                `fory:"id=2"`
    Phones []Person_PhoneNumber `fory:"id=7,type=list"`
    Pet    Animal               `fory:"id=8"`
}

func (m *Person) ToBytes() ([]byte, error) { ... }
func (m *Person) FromBytes(data []byte) error { ... }

Unions generate typed case structs with constructors/accessors/visitor APIs:

type AnimalCase uint32

type Animal struct {
    case_ AnimalCase
    value any
}

func DogAnimal(v *Dog) Animal { ... }
func CatAnimal(v *Cat) Animal { ... }

func (u Animal) Case() AnimalCase { ... }
func (u Animal) AsDog() (*Dog, bool) { ... }
func (u Animal) Visit(visitor AnimalVisitor) error { ... }

Registration

Generated registration function:

func RegisterTypes(f *fory.Fory) error {
    if err := f.RegisterUnion(Animal{}, 106, fory.NewUnionSerializer(...)); err != nil {
        return err
    }
    if err := f.RegisterEnum(Person_PhoneType(0), 101); err != nil {
        return err
    }
    if err := f.RegisterStruct(Person_PhoneNumber{}, 102); err != nil {
        return err
    }
    if err := f.RegisterStruct(Person{}, 100); err != nil {
        return err
    }
    return nil
}

For schemas without explicit [id=...], generated registration uses computed numeric IDs:

if err := f.RegisterEnum(Status(0), 1124725126); err != nil { ... }
if err := f.RegisterUnion(Wrapper{}, 1471345060, fory.NewUnionSerializer(...)); err != nil { ... }
if err := f.RegisterStruct(Envelope{}, 3022445236); err != nil { ... }
if err := f.RegisterUnion(Envelope_Detail{}, 1609214087, fory.NewUnionSerializer(...)); err != nil { ... }
if err := f.RegisterStruct(Envelope_Payload{}, 2862577837); err != nil { ... }

If option enable_auto_type_id = false; is set:

if err := f.RegisterStructByName(Config{}, "myapp.models.Config"); err != nil { ... }
if err := f.RegisterUnionByName(Holder{}, "myapp.models.Holder", fory.NewUnionSerializer(...)); err != nil { ... }

go_nested_type_style controls nested type naming:

option go_nested_type_style = "camelcase";

The CLI flag --go_nested_type_style overrides this schema option when both are set.

Usage

person := &Person{
    Name: "Alice",
    Pet:  DogAnimal(&Dog{Name: "Rex"}),
}

data, err := person.ToBytes()
if err != nil {
    panic(err)
}
var restored Person
if err := restored.FromBytes(data); err != nil {
    panic(err)
}

gRPC Service Companions

With --grpc, Go emits <module>_grpc.go containing the generated CodecV2, client and server interfaces, stream types, descriptors, and registration helpers. See Go gRPC for codec configuration and usage.