Generating Protobufs with entproto

    The first thing we need to do is to add an entproto.Message() annotation. This is our opt-in to Protobuf schema generation, we don’t necessarily want to generate proto messages or gRPC service definitions from all of our schema entities, and this annotation gives us that control. To add it, append to ent/schema/user.go:

    ent/schema/user.go

    Next, we need to annotate each field and assign it a field number. Recall that when defining a protobuf message type, each field must be assigned a unique number. To do that, we add an entproto.Field annotation on each field. Update the Fields in ent/schema/user.go:

    ent/schema/user.go

    1. // Fields of the User.
    2. func (User) Fields() []ent.Field {
    3. return []ent.Field{
    4. field.String("name").
    5. Unique().
    6. Annotations(
    7. entproto.Field(2),
    8. ),
    9. field.String("email_address").
    10. Unique().
    11. Annotations(
    12. entproto.Field(3),
    13. ),
    14. }

    Notice that we did not start our field numbers from 1, this is because implicitly creates the ID field for the entity, and that field is automatically assigned the number 1. We can now generate our protobuf message type definitions. To do that, we will add to ent/generate.go a go:generate directive that invokes the entproto command-line tool. It should now look like this:

    ent/generate.go

    1. package ent
    2. //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema
    3. //go:generate go run -mod=mod entgo.io/contrib/entproto/cmd/entproto -path ./schema

    Observe that a new directory was created which will contain all protobuf related generated code: ent/proto. It now contains:

    1. ent/proto
    2. └── entpb
    3. ├── entpb.proto
    4. └── generate.go

    Two files were created. Let’s look at their contents:

    ent/proto/entpb/entpb.proto

    1. // Code generated by entproto. DO NOT EDIT.
    2. syntax = "proto3";
    3. package entpb;
    4. option go_package = "ent-grpc-example/ent/proto/entpb";
    5. int32 id = 1;
    6. string user_name = 2;
    7. string email_address = 3;
    8. }

    Nice! A new .proto file containing a message type definition that maps to our User schema was created!

    ent/proto/entpb/generate.go

    A new generate.go file was created with an invocation to protoc, the protobuf code generator instructing it how to generate Go code from our .proto file. For this command to work, we must first install protoc as well as 3 protobuf plugins: protoc-gen-go (which generates Go Protobuf structs), protoc-gen-go-grpc (which generates Go gRPC service interfaces and clients), and protoc-gen-entgrpc (which generates an implementation of the service interface). If you do not have these installed, please follow these directions:

    • To install protoc-gen-entgrpc, run:

      1. go install entgo.io/contrib/entproto/cmd/protoc-gen-entgrpc@latest

    After installing these dependencies, we can re-run code-generation:

    1. go generate ./...

    Observe that a new file named ent/proto/entpb/entpb.pb.go was created which contains the generated Go structs for our entities.

    Let’s write a test that uses it to make sure everything is wired correctly. Create a new file named pb_test.go and write:

    To run it:

    1. go test ./...