Earlier quoted context omitted.
What have you find too complex about protobuffs? Unfortunately twirp is go-only.
It's go-only for now. Protobufs includes a code gen step, which is a burden on project tooling and workflow and it's not very fun using the types it generates or writing boilerplate to convert to the types you'd prefer. Also, I'm not sure about twirp, but protobufs doesn't have a good way to model interface or sum types last I checked.
message MyThing { oneof sum_type { TypeOne type_one = 1; TypeTwo type_two = 2; } }
The lack of inheritance seems awkward at first, but with oneof it isn't much of a blocker. The APIs for this aren't always great -- Go's in particular feel kind of awkward (IMO). Java's are nice -- it's a separate enum you can switch over.
An example from a Go project of mine:
switch req.StartAt.(type) {
case *pb.GetLogsRequest_Timestamp:
t, err := types.TimestampFromProto(req.GetTimestamp())
if err != nil {
return nil, errors.Errorf("Bad timestamp: %v", req.GetTimestamp())
}
filter.Timestamp = t
case *pb.GetLogsRequest_Offset:
filter.StartOffset = req.GetOffset()
case *pb.GetLogsRequest_Position_:
switch req.GetPosition() {
case pb.GetLogsRequest_LATEST:
filter.Position = LATEST
case pb.GetLogsRequest_EARLIEST:
filter.Position = EARLIEST
}
case nil:
default:
return nil, errors.Errorf("Unknown GetLogsRequest.StartAt type.")
}
}