Generación de un servicio gRPC
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Generar estructuras Protobuf a partir de nuestro ent.Schema puede ser útil, pero lo que realmente nos interesa es obtener un servidor real que pueda crear, leer, actualizar y eliminar entidades de una base de datos real. Para lograrlo, ¡solo necesitamos actualizar una línea de código! Cuando anotamos un esquema con entproto.Service, le indicamos a la generación de código de entproto que queremos generar una definición de servicio gRPC. Luego, protoc-gen-entgrpc leerá nuestra definición y generará una implementación del servicio. Edita ent/schema/user.go y modifica las Annotations del esquema:
func (User) Annotations() []schema.Annotation {
return []schema.Annotation{
entproto.Message(),
entproto.Service(), // <-- add this
}
}
Ahora vuelve a ejecutar la generación de código:
go generate ./...
Observa algunos cambios interesantes en ent/proto/entpb:
ent/proto/entpb
├── entpb.pb.go
├── entpb.proto
├── entpb_grpc.pb.go
├── entpb_user_service.go
└── generate.go
Primero, entproto añadió una definición de servicio a entpb.proto:
service UserService {
rpc Create ( CreateUserRequest ) returns ( User );
rpc Get ( GetUserRequest ) returns ( User );
rpc Update ( UpdateUserRequest ) returns ( User );
rpc Delete ( DeleteUserRequest ) returns ( google.protobuf.Empty );
rpc List ( ListUserRequest ) returns ( ListUserResponse );
rpc BatchCreate ( BatchCreateUsersRequest ) returns ( BatchCreateUsersResponse );
}
Además, se crearon dos archivos nuevos. El primero, entpb_grpc.pb.go, contiene el stub del cliente gRPC y la definición de la interfaz. Si abres el archivo, encontrarás en él (entre muchas otras cosas):
// UserServiceClient is the client API for UserService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please
// refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type UserServiceClient interface {
Create(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*User, error)
Get(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*User, error)
Update(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*User, error)
Delete(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
List(ctx context.Context, in *ListUserRequest, opts ...grpc.CallOption) (*ListUserResponse, error)
BatchCreate(ctx context.Context, in *BatchCreateUsersRequest, opts ...grpc.CallOption) (*BatchCreateUsersResponse, error)
}
El segundo archivo, entpub_user_service.go, contiene una implementación generada para esta interfaz. Por ejemplo, una implementación para el método Get:
// Get implements UserServiceServer.Get
func (svc *UserService) Get(ctx context.Context, req *GetUserRequest) (*User, error) {
var (
err error
get *ent.User
)
id := int(req.GetId())
switch req.GetView() {
case GetUserRequest_VIEW_UNSPECIFIED, GetUserRequest_BASIC:
get, err = svc.client.User.Get(ctx, id)
case GetUserRequest_WITH_EDGE_IDS:
get, err = svc.client.User.Query().
Where(user.ID(id)).
Only(ctx)
default:
return nil, status.Error(codes.InvalidArgument, "invalid argument: unknown view")
}
switch {
case err == nil:
return toProtoUser(get)
case ent.IsNotFound(err):
return nil, status.Errorf(codes.NotFound, "not found: %s", err)
default:
return nil, status.Errorf(codes.Internal, "internal error: %s", err)
}
}
¡Nada mal! A continuación, creemos un servidor gRPC que pueda atender las solicitudes de nuestro servicio.