生成 gRPC 服务
由 ent.Schema 生成 Protobuf 结构体是很有用的,但是我们真正感兴趣的是得到一个实际可以从一个真实数据库中创建、读取、更新和删除实体的实际的服务器。
为做到这一点,我们只需要更新一行代码!当我们使用 entproto.Service 注解一个模式,我们告诉 entproto 代码生成我们对生成 gRPC 服务定义感兴趣,它会从 protoc-gen-entgrpc 读取我们的定义并生成服务实现。
编辑 ent/schema/user.go 并修改模式的 Annotations:
ent/schema/user.go
func (User) Annotations() []schema.Annotation {
return []schema.Annotation{
entproto.Message(),
entproto.Service(), // <-- add this
}
}
现在再次运行代码生成:
go generate ./...
可以看到 ent/proto/entpb 发生了有趣的改变:
ent/proto/entpb
├── entpb.pb.go
├── entpb.proto
├── entpb_grpc.pb.go
├── entpb_user_service.go
└── generate.go
首先 entproto 向 entpb.proto 添加了一个服务定义:
ent/proto/entpb/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 );
}
另外两个新的文件被创建了。第一个文件是 entpb_grpc.pb.go,它包含了 gRPC 客户端存根和接口定义。
如果你打开这个文件你可以可以看到如下内容(和其他许多内容):
ent/proto/entpb/entpb_grpc.pb.go
// 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)
}
第二个文件是 entpub_user_service.go,它包含了为接口创建的实现。
例如 Get 方法的实现:
ent/proto/entpb/entpb_user_service.go
// 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)
}
}
很好!下一步我们将创建一个 gRPC 服务器可以为服务提供请求。