Saltar al contenido principal

Generación de Protobufs con entproto

[Traducción Beta No Oficial]

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Dado que los esquemas de Ent y Protobuf no son idénticos, debemos añadir algunas anotaciones en nuestro esquema para ayudar a entproto a determinar exactamente cómo generar las definiciones de Protobuf (llamadas "Mensajes" en la terminología de protobuf).

Lo primero que necesitamos hacer es añadir una anotación entproto.Message(). Este es nuestro opt-in para la generación del esquema Protobuf; no necesariamente queremos generar mensajes proto o definiciones de servicios gRPC para todas nuestras entidades de esquema, y esta anotación nos da ese control. Para añadirla, agrega en ent/schema/user.go:

ent/schema/user.go
func (User) Annotations() []schema.Annotation {
return []schema.Annotation{
entproto.Message(),
}
}

A continuación, debemos anotar cada campo y asignarle un número de campo. Recuerda que al definir un tipo de mensaje protobuf, cada campo debe tener un número único. Para ello, añadimos una anotación entproto.Field en cada campo. Actualiza los Fields en ent/schema/user.go:

ent/schema/user.go
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name").
Unique().
Annotations(
entproto.Field(2),
),
field.String("email_address").
Unique().
Annotations(
entproto.Field(3),
),
}
}

Observa que no comenzamos nuestros números de campo desde 1, esto se debe a que ent crea implícitamente el campo ID para la entidad, y a ese campo se le asigna automáticamente el número 1. Ahora podemos generar nuestras definiciones de tipos de mensajes protobuf. Para hacerlo, añadiremos en ent/generate.go una directiva go:generate que invoque la herramienta de línea de comandos entproto. Ahora debería verse así:

ent/generate.go
package ent

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

Vamos a regenerar nuestro código:

go generate ./...

Observa que se ha creado un nuevo directorio que contendrá todo el código generado relacionado con protobuf: ent/proto. Ahora contiene:

ent/proto
└── entpb
├── entpb.proto
└── generate.go

Se crearon dos archivos. Veamos su contenido:

ent/proto/entpb/entpb.proto
// Code generated by entproto. DO NOT EDIT.
syntax = "proto3";

package entpb;

option go_package = "ent-grpc-example/ent/proto/entpb";

message User {
int32 id = 1;

string user_name = 2;

string email_address = 3;
}

¡Genial! Se ha creado un nuevo archivo .proto que contiene una definición de tipo de mensaje que se corresponde con nuestro esquema User.

ent/proto/entpb/generate.go
package entpb
//go:generate protoc -I=.. --go_out=.. --go-grpc_out=.. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative --entgrpc_out=.. --entgrpc_opt=paths=source_relative,schema_path=../../schema entpb/entpb.proto

Se ha creado un nuevo archivo generate.go con una invocación a protoc, el generador de código protobuf, que le indica cómo generar código Go desde nuestro archivo .proto. Para que este comando funcione, primero debemos instalar protoc y 3 plugins de protobuf: protoc-gen-go (que genera estructuras Protobuf de Go), protoc-gen-go-grpc (que genera interfaces de servicio gRPC de Go y clientes), y protoc-gen-entgrpc (que genera una implementación de la interfaz de servicio). Si no los tienes instalados, sigue estas instrucciones:

Tras instalar estas dependencias, podemos volver a ejecutar la generación de código:

go generate ./...

Observa que se ha creado un nuevo archivo llamado ent/proto/entpb/entpb.pb.go que contiene las estructuras Go generadas para nuestras entidades.

Observa que se ha creado un nuevo archivo llamado pb_test.go que contiene las estructuras Go generadas para nuestras entidades.

package main

import (
"testing"

"ent-grpc-example/ent/proto/entpb"
)

func TestUserProto(t *testing.T) {
user := entpb.User{
Name: "rotemtam",
EmailAddress: "rotemtam@example.com",
}
if user.GetName() != "rotemtam" {
t.Fatal("expected user name to be rotemtam")
}
if user.GetEmailAddress() != "rotemtam@example.com" {
t.Fatal("expected email address to be rotemtam@example.com")
}
}

Para ejecutarlo:

go get -u ./... # install deps of the generated package
go test ./...

¡Bravo! La prueba ha pasado. Hemos generado con éxito estructuras Protobuf de Go funcionales a partir de nuestro esquema Ent. A continuación, veamos cómo generar automáticamente un servidor gRPC CRUD funcional a partir de nuestro esquema.