メインコンテンツへスキップする

gRPCサービスの生成

ent.SchemaからProtobuf構造体を生成するのは便利ですが、私たちが本当に興味を持っているのは、実際にデータベースからエンティティを作成、読み取り、更新、削除できる実際のサーバーを手に入れることですよね。 それは、たった1行のコードを更新するだけで可能です! entproto.Serviceでスキーマをアノテートすると、gRPCサービス定義の生成に興味があることをentprotoコードジェネレーターに伝え、protoc-gen-entgrpcが定義を読み込んでサービス実装を生成します。 ent/schema/user.goで、スキーマのAnnotationsを修正します。

func (User) Annotations() []schema.Annotation {
return []schema.Annotation{
entproto.Message(),
entproto.Service(), // <-- これを追加します
}
}

ここでコード生成を再実行します。

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にサービス定義を追加します:

service UserService {
rpc Create ( CreateUserRequest ) returns ( User );

rpc Get ( GetUserRequest ) returns ( User );

rpc Update ( UpdateUserRequest ) returns ( User );

rpc Delete ( DeleteUserRequest ) returns ( google.protobuf.Empty );
}

さらに、2つの新しいファイルが作成されました。 1つ目のent_grpc.pb.goには、gRPCクライアントスタブとインターフェース定義が含まれています。 ファイルを開くと、その中に見つけることができます(他の多くのコードの一部として)。

// 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)
}

2つ目のファイル、entpub_user_service.goには、このインターフェイスの実装が生成されています。 例えば、Getメソッドの実装です:

// Get implements UserServiceServer.Get
func (svc *UserService) Get(ctx context.Context, req *GetUserRequest) (*User, error) {
var (
err error
get *ent.User
)
switch req.GetView() {
case GetUserRequest_VIEW_UNSPECIFIED, GetUserRequest_BASIC:
get, err = svc.client.User.Get(ctx, int(req.GetId()))
case GetUserRequest_WITH_EDGE_IDS:
get, err = svc.client.User.Query().
Where(user.ID(int(req.GetId()))).
Only(ctx)
default:
return nil, status.Errorf(codes.InvalidArgument, "invalid argument: unknown view")
}
switch {
case err == nil:
return toProtoUser(get), nil
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サーバーを作成しましょう。