はじめに
今回は、私が現場で使っているprotoc-gen-validate(PGV)についてまとめてみました。 復習がてらまとめていきます。
PGVは.proto
ファイルにバリデーションルールを定義するだけで、各言語のバリデーションコードを自動生成できちゃう優れもの。
PGVってなに?
- PGVは、Protocol Buffersのコード生成プラグインの1つ
.proto
ファイルで定義されたメッセージに対して、バリデーションルールを指定できる- そのルールを元に、PGVが各言語のバリデーションコードを自動生成してくれる
PGVの使い方
インストール方法
- PGVは、Go言語で実装されてて、シングルバイナリで提供されてます
- 以下のコマンドでインストールできる
go install github.com/envoyproxy/protoc-gen-validate@latest
- HomebrewやDocker経由でもインストールできるみたいっすね
.proto
ファイルでのバリデーションルールの定義方法
.proto
ファイルの中で、こんな感じでバリデーションルールを定義します
message Person { uint64 id = 1 [(validate.rules).uint64.gt = 999]; string email = 2 [(validate.rules).string.email = true]; string name = 3 [(validate.rules).string = {min_len: 5, max_len: 20}]; message Address { string street = 1 [(validate.rules).string.min_len = 5]; string city = 2 [(validate.rules).string.min_len = 5]; string state = 3 [(validate.rules).string = {in: ["CA", "NY"]}]; } Address address = 4 [(validate.rules).message.required = true]; }
上の例だと、Person
メッセージの各フィールドにバリデーションルールを定義してる感じっすね。
例えばid
は999より大きい整数、email
はメールアドレスの形式を満たす必要があるといった感じ。
コード生成の方法
定義したバリデーションルールを元にコードを生成するには、protoc
コマンドに--validate_out
オプションを指定します。
Go言語の場合はこんな感じ。
protoc \ -I . \ -I ${GOPATH}/src \ -I ${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate \ --go_out=":./gen" \ --validate_out="lang=go:./gen" \ person.proto
上のコマンドを実行すると、gen
ディレクトリ以下にperson.pb.go
とperson.pb.validate.go
が生成されるわけですね
生成されたバリデーションコードの使用方法
- 生成されたコードは、こんな感じで使えます
p := &Person{ Id: 1000, Email: "john@example.com", Name: "John Doe", Address: &Address{ Street: "123 Main St", City: "Anytown", State: "CA", }, } err := p.Validate() if err != nil { // バリデーションエラー処理 }
Validate
メソッドを呼び出すと、Person
オブジェクトのバリデーションが行われるんです
バリデーションエラーがあれば、err
にエラー内容が格納される、って感じっすね
バリデーションルールの定義例と、それによって防げるエラー
以下は、よくあるバリデーションルールの定義例と、それによって防げるエラーの例です。
文字列フィールドの長さを制限する
string name = 1 [(validate.rules).string.min_len = 1, (validate.rules).string.max_len = 100];
これにより、空文字列や長すぎる文字列によるエラーを防げます。
整数フィールドの範囲を制限する
int32 age = 1 [(validate.rules).int32.gte = 0, (validate.rules).int32.lte = 150];
これにより、負の数や非現実的な値によるエラーを防げます。
繰り返しフィールドの要素数を制限する
repeated string tags = 1 [(validate.rules).repeated.min_items = 1, (validate.rules).repeated.max_items = 5];
これにより、空のリストや大量の要素によるエラーを防げます。
メッセージフィールドを必須にする
Address address = 1 [(validate.rules).message.required = true];
これにより、重要なフィールドの欠落によるエラーを防げます。
まとめ
- PGVを使えば、
.proto
ファイルにバリデーションルールを定義するだけで、各言語のバリデーションコードを自動生成できちゃう - PGVを使うことで、アプリケーションコードからバリデーションロジックを分離でき、コードの可読性とメンテナンス性が向上する
- Protocol Buffersを使ってるプロジェクトには、PGVが最適かも
※ 公式では新しいプロジェクトは後継のprotovalidateを使ってね!とありました。https://github.com/bufbuild/protovalidate
ってことで、PGVについてざっくりまとめてみました!私のように、APIのスキーマ定義にprotobufを使ってる勢には、かなり便利なツールだと思います。