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

entprotoでProtobusfsを生成する

EntとProtobufのスキーマは同一ではないので、entprotoがProtobufの定義(Protobufの用語では「メッセージ」と呼ばれます)を生成する方法を正確に把握できるように、スキーマにいくつかのアノテーションを付与する必要があります。

まず必要なのは、entproto.Message()アノテーションです。 これはProtobufスキーマ生成へのオプトインです。必ずしもすべてのスキーマ・エンティティからProtoメッセージやgRPCサービス定義を生成したいわけではない場合、このアノテーションによってその制御が可能になります。 このアノテーションは、ent/schema/user.go に追加します。

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

次に、各フィールドにアノテーションを付けて、フィールド番号を割り当てます。 protobufメッセージタイプを定義する際、各フィールドには一意の番号を割り当てる必要があることを思い出してください。 これを行うために、各フィールドにentproto.Fieldアノテーションを追加します。 ent/schema/user.goFieldsを更新します。

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

数字が2から始まるのは、entが暗黙のうちにエンティティのIDフィールドを作成し、そのフィールドに自動的に1が割り当てられるためです。 これで、protobufメッセージタイプの定義を生成できます。 そのためには、ent/generate.goに、entprotoコマンドラインツールを呼び出すgo:generateディレクティブを追加します。 以下のようになります:

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

コードを再生成してみましょう:

go generate ./...

すべてのprotobuf関連の生成コードを含む新しいディレクトリが作成されたことを確認してください。ent/protoです。 以下が含まれています:

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

2つのファイルが作成されました。 その内容を見てみましょう。

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

すばらしい! Userスキーマにマッピングするメッセージタイプ定義を含む新しい.protoファイルが作成されました!

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

新しく作成されたgenerate.go ファイルは、.proto ファイルから Go コードを生成する方法を指示する protobuf コードジェネレータprotocを呼び出します。 このコマンドを実行するためには、まずprotocと3つのprotobufプラグインをインストールする必要があります。protoc-gen-go(Go Protobuf構造体を生成)、protoc-gen-go-grpc(Go gRPCサービスインターフェースとクライアントを生成)、protoc-gen-entgrpc(サービスインターフェースの実装を生成)です。 これらがインストールされていない場合は、以下の指示に従ってください。

これらの依存関係をインストールした後、コード生成を再実行します。

go generate ./...

ent/proto/entpb/entpb.pb.goという新しいファイルが作成され、エンティティ用に生成されたGoの構造体が含まれていることを確認してください。

このファイルを使ったテストを書いて、すべてが正しく動いていることを確認しましょう。 pb_test.goという名前の新しいファイルを作り、以下のように書きます:

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

こちらを実行してください:

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

おめでとうございます! テストはpassしました。 Entスキーマから正しく機能するGo Protobuf構造体の生成に成功しました。 次に、スキーマから動作するCRUD gRPCサーバーを自動的に生成する方法を見てみましょう。