4. Codec Registry
When events are stored in a database (MongoDB, PostgreSQL), the framework needs to know how to convert your event data types to and from bytes. The codec registry maps event names to their Go types.
Register Events
Add a RegisterProductEvents function to product.go:
import "github.com/modernice/goes/codec"
func RegisterProductEvents(r codec.Registerer) {
codec.Register[ProductCreatedData](r, ProductCreated)
codec.Register[string](r, ProductRenamed)
codec.Register[int](r, PriceChanged)
codec.Register[StockAdjustedData](r, StockAdjusted)
}Wire It Up
In cmd/main.go, call the registration function:
import (
// ... existing imports ...
"github.com/yourname/shop"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
eventReg := codec.New()
// Register all event types.
shop.RegisterProductEvents(eventReg)
store := eventstore.New()
bus := eventbus.New()
store = eventstore.WithBus(store, bus)
// ...
}How It Works
codec.Register[T](registry, eventName) tells the registry:
"When you see an event named
eventName, the data is of typeT. Use JSON to serialize and deserialize it."
The generic type parameter T must match the type you use in your event data:
// These must match:
codec.Register[ProductCreatedData](r, ProductCreated)
// ^^^^^^^^^^^^^^^^^^
aggregate.Next(p, ProductCreated, ProductCreatedData{...})
// ^^^^^^^^^^^^^^^^^^
event.ApplyWith(p, p.created, ProductCreated)
// handler signature: func(evt event.Of[ProductCreatedData])
// ^^^^^^^^^^^^^^^^^^Default Serialization
The codec uses JSON by default. Your event data types just need to be JSON-serializable — exported fields with standard Go types. If you need a different format, you can configure it:
eventReg := codec.New(codec.Default(
customMarshal, // func(any) ([]byte, error)
customUnmarshal, // func([]byte, any) error
))Or implement codec.Marshaler / codec.Unmarshaler on individual types for per-type customization.
Convention
We recommend adding a Register<Aggregate>Events function to each aggregate file. As we add more aggregates, cmd/main.go will call each one:
shop.RegisterProductEvents(eventReg)
shop.RegisterOrderEvents(eventReg) // coming in chapter 7
shop.RegisterCustomerEvents(eventReg) // coming in chapter 8Next
Events are registered. Now let's persist and fetch our aggregates using repositories.