protovalidate 逆引きリファレンス(proto3)

に公開

今回は、protovalidate を使って Proto を定義する中で、毎回公式ドキュメントを確認するのが手間だと感じていました。
そこで、逆引き形式でサッと確認できるリファレンスがあれば便利だなと思い、この記事を作成してみました😊!

はじめに

protovalidate とは?

protovalidate は、Protocol Buffers に対するバリデーションルールを定義できる仕組みで、
Buf が提供する buf.validate 拡張に基づいています。
protobuf ファイルに制約(例:必須、最小値、最大長など)を直接書くことができます。

Protobufで唯一広く使用されている検証ライブラリであるprotoc-gen-validateの次世代版です。

https://github.com/bufbuild/protovalidate

https://buf.build/bufbuild/protovalidate/docs/main:buf.validate#buf.validate.AnyRules

こんな人におすすめ

  • Protobuf や gRPC を使っているが、バリデーションの記述に迷っている方
  • API の入力チェックをコードレスで共通化したい方

protoの定義時に、型安全に定義可能になります ⭐️

AnyRules

許可された型のいずれかである必要があるとき

The value field must have a type_url equal to one of the specified values.

google.protobuf.Any value = 1 [(buf.validate.field).any.in = ["type.googleapis.com/MyType1", "type.googleapis.com/MyType2"]];

禁止された型のいずれかでない必要があるとき

The field value must not have a type_url equal to any of the specified values.generated.

google.protobuf.Any value = 1 [(buf.validate.field).any.not_in = ["type.googleapis.com/ForbiddenType1", "type.googleapis.com/ForbiddenType2"]];

BoolRules

真偽値がtrueに限定されるとき

value must equal true

bool value = 1 [(buf.validate.field).bool.const = true];

真偽値がfalseに限定されるとき

value must equal false

bool value = 1 [(buf.validate.field).bool.const = false];

BytesRules

固定のバイト列だけを許可したいとき

value must be "\x01\x02\x03\x04"

bytes value = 1 [(buf.validate.field).bytes.const = "\x01\x02\x03\x04"];

バイト列の長さを指定のバイト数に制限したいとき

value length must be 4 bytes.

optional bytes value = 1 [(buf.validate.field).bytes.len = 4];

バイト列の最小長さを制限したいとき

value length must be at least 2 bytes.

optional bytes value = 1 [(buf.validate.field).bytes.min_len = 2];

バイト列の最大長さを制限したいとき

value must be at most 6 bytes.

optional bytes value = 1 [(buf.validate.field).bytes.max_len = 6];

正規表現でバイト列を制限したいとき

value must match regex pattern

optional bytes value = 1 [(buf.validate.field).bytes.pattern = "^[a-zA-Z0-9]+$"];

特定のバイト列で始まることを確認したいとき

value must start with the byte prefix "\x01\x02"

optional bytes value = 1 [(buf.validate.field).bytes.prefix = "\x01\x02"];

特定のバイト列で終わることを確認したいとき

value must end with the byte suffix "\x03\x04"

optional bytes value = 1 [(buf.validate.field).bytes.suffix = "\x03\x04"];

特定のバイト列を含む必要があるとき

value must contain the byte sequence \x02\x03

optional bytes value = 1 [(buf.validate.field).bytes.contains = "\x02\x03"];

許可されたバイト列のいずれかに一致させたいとき

value must in ["\x01\x02", "\x02\x03", "\x03\x04"]

optional bytes value = 1 [(buf.validate.field).bytes.in = {"\x01\x02", "\x02\x03", "\x03\x04"}];

禁止されたバイト列のいずれかに一致しないようにしたいとき

value must not in ["\x01\x02", "\x02\x03", "\x03\x04"]

optional bytes value = 1 [(buf.validate.field).bytes.not_in = {"\x01\x02", "\x02\x03", "\x03\x04"}];

IPv4 または IPv6 の形式であることを検証したいとき

value must be a valid IP address

optional bytes value = 1 [(buf.validate.field).bytes.ip = true];

IPv4 の形式であることを検証したいとき

value must be a valid IPv4 address

optional bytes value = 1 [(buf.validate.field).bytes.ipv4 = true];

IPv6 の形式であることを検証したいとき

value must be a valid IPv6 address

optional bytes value = 1 [(buf.validate.field).bytes.ipv6 = true];

DoubleRules

特定の値と完全に一致させたいとき

value must equal 42.0

double value = 1 [(buf.validate.field).double.const = 42.0];

特定の値より小さい値に制限したいとき

value must be less than 10.0

 double value = 1 [(buf.validate.field).double.lt = 10.0];

特定の値以下に制限したいとき

value must be less than or equal to 10.0

double value = 1 [(buf.validate.field).double.lte = 10.0];

特定の値より大きい値に制限したいとき

value must be greater than 5.0 [double.gt]

double value = 1 [(buf.validate.field).double.gt = 5.0];

特定の値以上に制限したいとき

value must be greater than or equal to 5.0 [double.gte]

double value = 1 [(buf.validate.field).double.gte = 5.0];

特定の範囲内の値に制限したいとき

value must be greater than 5.0 and less than 10.0 [double.gt_lt]

double value = 1 [(buf.validate.field).double = { gt: 5.0, lt: 10.0 }];

許可された値のいずれかに一致させたいとき

value must be in list [1.0, 2.0, 3.0]

double value = 1 [(buf.validate.field).double = { in: [1.0, 2.0, 3.0] }];

禁止された値のいずれかに一致しないようにしたいとき

value must not be in list [1.0, 2.0, 3.0]

double value = 1 [(buf.validate.field).double = { not_in: [1.0, 2.0, 3.0] }];

無限大や NaN を許可せず、有限値に制限したいとき

value must be a finite number (not NaN or Infinity) [double.finite]

double value = 1 [(buf.validate.field).double.finite = true];

DurationRules

指定された秒数と完全に一致させたいとき

value must equal 5s

google.protobuf.Duration value = 1 [(buf.validate.field).duration.const = "5s"];

指定された秒数より短い値に制限したいとき

value must be less than 5s

google.protobuf.Duration value = 1 [(buf.validate.field).duration.lt = "5s"];

指定された秒数以下の値に制限したいとき

value must be less than or equal to 10s

google.protobuf.Duration value = 1 [(buf.validate.field).duration.lte = "10s"];

指定された秒数より長い値に制限したいとき

duration must be greater than 5s [duration.gt]

google.protobuf.Duration value = 1 [(buf.validate.field).duration.gt = { seconds: 5 }];

指定された秒数以上の値に制限したいとき

duration must be greater than or equal to 5s [duration.gte]

google.protobuf.Duration value = 1 [(buf.validate.field).duration.gte = { seconds: 5 }];

指定された時間の範囲内に制限したいとき

duration must be greater than or equal to 5s and less than 10s [duration.gte_lt]

google.protobuf.Duration value = 1 [(buf.validate.field).duration = { gte: { seconds: 5 }, lt: { seconds: 10 } }];

許可された複数の時間のいずれかに一致させたいとき

value must be in list [1s, 2s, 3s]

google.protobuf.Duration value = 1 [(buf.validate.field).duration.in = ["1s", "2s", "3s"]];

禁止された複数の時間のいずれかに一致しないようにしたいとき

value must not be in list [1s, 2s, 3s]

google.protobuf.Duration value = 1 [(buf.validate.field).duration.not_in = ["1s", "2s", "3s"]];

EnumRules

enum MyEnum {
  MY_ENUM_UNSPECIFIED = 0;
  MY_ENUM_VALUE1 = 1;
  MY_ENUM_VALUE2 = 2;
}

特定の値だけを許可したいとき

The field value must be exactly MY_ENUM_VALUE1.

MyEnum value = 1 [(buf.validate.field).enum.const = 1];

Enum に定義された値のみを許可したいとき(未定義の数値はエラー)

The field value must be a defined value of MyEnum.

ExEnum value = 1 [(buf.validate.field).enum.defined_only = true];

指定した Enum 値のいずれかに一致させたいとき

The field value must be equal to one of the specified values.

MyEnum value = 1 [(buf.validate.field).enum = { in: [1, 2]}];

指定した Enum 値のいずれかを除外したいとき

The field value must not be equal to any of the specified values.

MyEnum value = 1 [(buf.validate.field).enum = { not_in: [1, 2]}];

Int32Rules

特定の値である必要があるとき

value must equal 42

int32 value = 1 [(buf.validate.field).int32.const = 42];

特定の値より小さい値に制限したいとき

value must be less than 10

int32 value = 1 [(buf.validate.field).int32.lt = 10];

特定の値以下に制限したいとき(その値も含む)

value must be less than or equal to 10

int32 value = 1 [(buf.validate.field).int32.lte = 10];

特定の値より大きい値に制限したいとき

value must be greater than 5 [int32.gt]

int32 value = 1 [(buf.validate.field).int32.gt = 5];

特定の値以上に制限したいとき(その値も含む)

value must be greater than or equal to 5 [int32.gte]

int32 value = 1 [(buf.validate.field).int32.gte = 5];

特定の範囲内の値に制限したいとき

value must be greater than 5 and less than 10 [int32.gt_lt]

int32 value = 1 [(buf.validate.field).int32 = { gt: 5, lt: 10 }];

許可された数値のいずれかに一致させたいとき

value must be in list [1, 2, 3]

int32 value = 1 [(buf.validate.field).int32 = { in: [1, 2, 3] }];

禁止された数値のいずれかに一致しないようにしたいとき

value must not be in list [1, 2, 3]

int32 value = 1 [(buf.validate.field).int32 = { not_in: [1, 2, 3] }];

MapRules

key-value ペアの最小数を指定したいとき

The field value must have at least 2 key-value pairs.

map<string, string> value = 1 [(buf.validate.field).map.min_pairs = 2];

key-value ペアの最大数を指定したいとき

The field value must have at most 3 key-value pairs.

map<string, string> value = 1 [(buf.validate.field).map.max_pairs = 3];

key の長さや文字数に制限をつけたいとき

The keys in the field value must follow the specified constraints.


map<string, string> value = 1 [(buf.validate.field).map.keys = {
	string: {
	min_len: 3
	max_len: 10
	}
}];

value の長さや文字数に制限をつけたいとき

The values in the field value must follow the specified constraints.

map<string, string> value = 1 [(buf.validate.field).map.values = {
	string: {
	min_len: 5
	max_len: 20
	}
}];

RepeatedRules

リストの最小要素数を指定したいとき

value must contain at least 2 items

repeated string value = 1 [(buf.validate.field).repeated.min_items = 2];

リストの最大要素数を指定したいとき

value must contain no more than 3 item(s)

repeated string value = 1 [(buf.validate.field).repeated.max_items = 3];

リスト内の要素をすべてユニークにしたいとき

repeated value must contain unique items

repeated string value = 1 [(buf.validate.field).repeated.unique = true];

リスト内の各要素に対して特定の制約(長さなど)を与えたいとき

The items in the field value must follow the specified constraints.

repeated string value = 1 [(buf.validate.field).repeated.items = {
	string: {
	min_len: 3
	max_len: 10
	}
}];

StringRules

特定の文字列のみ許可したいとき

value must equal hello

string value = 1 [(buf.validate.field).string.const = "ok"];

文字数を正確に指定したいとき

value length must be exactly 5 characters

string value = 1 [(buf.validate.field).string.len = 5];

最小の文字数を指定したいとき

value length must be at least 3 characters

string value = 1 [(buf.validate.field).string.min_len = 3];

最大の文字数を指定したいとき

value length must be at most 10 characters

string value = 1 [(buf.validate.field).string.max_len = 10];

バイト数で正確に指定したいとき

value length must be exactly 6 bytes

string value = 1 [(buf.validate.field).string.len_bytes = 6];

最小バイト数を指定したいとき

value length must be at least 4 bytes

string value = 1 [(buf.validate.field).string.min_bytes = 4];

最大バイト数を指定したいとき

value length must be at most 8 bytes

string value = 1 [(buf.validate.field).string.max_bytes = 8];

正規表現パターンに一致させたいとき

value must match regex pattern

string value = 1 [(buf.validate.field).string.pattern = "^[a-zA-Z]+$"];

指定の接頭辞(prefix)で始まる必要があるとき

value must start with pre

string value = 1 [(buf.validate.field).string.prefix = "pre"];

指定の接尾辞(suffix)で終わる必要があるとき

value must end with post

string value = 1 [(buf.validate.field).string.suffix = "post"];

指定の文字列を含んでいる必要があるとき

value must contain substring inside

string value = 1 [(buf.validate.field).string.contains = "inside"];

指定の文字列を含んではいけないとき

value must not contain substring inside

string value = 1 [(buf.validate.field).string.not_contains = "inside"];

許可リスト内の文字列のみ許可したいとき

value must be in list ["apple", "banana"]

string value = 1 [
  (buf.validate.field).string.in = "apple",
  (buf.validate.field).string.in = "banana"
];

禁止リストに含まれる文字列はNGにしたいとき

value must not be in list ["orange", "grape"]

string value = 1 [
  (buf.validate.field).string.not_in = "orange",
  (buf.validate.field).string.not_in = "grape"
];

メールアドレスの形式にしたいとき

value must be a valid email address

string value = 1 [(buf.validate.field).string.email = true];

ホスト名の形式にしたいとき

value must be a valid hostname

string value = 1 [(buf.validate.field).string.hostname = true];

IPアドレス(IPv4 または IPv6)の形式にしたいとき

value must be a valid IP address

string value = 1 [(buf.validate.field).string.ip = true];

IPv4アドレスの形式にしたいとき

value must be a valid IPv4 address

string value = 1 [(buf.validate.field).string.ipv4 = true];

IPv6形式のみ許容したいとき

value must be a valid IPv6 address

string value = 1 [(buf.validate.field).string.ipv6 = true];

URI形式を確認したいとき

value must be a valid URI

string value = 1 [(buf.validate.field).string.uri = true];

URI参照の形式を確認したいとき

value must be a valid URI Reference

string value = 1 [(buf.validate.field).string.uri_ref = true];

ホスト名またはIPアドレスのどちらかである必要があるとき

value must be a valid hostname or IP address

string value = 1 [(buf.validate.field).string.address = true];

UUID(標準形式)の形式にしたいとき

value must be a valid UUID

string value = 1 [(buf.validate.field).string.uuid = true];

UUID(ハイフンなし32桁)の形式にしたいとき

value must be a valid trimmed UUID

string value = 1 [(buf.validate.field).string.tuuid = true];

IPアドレス+プレフィックス長(CIDR形式)にしたいとき

value must be a valid IP address with prefix length (e.g., 192.0.2.0/24)

string value = 1 [(buf.validate.field).string.ip_with_prefixlen = true];

IPv4アドレス+プレフィックス長にしたいとき

value must be a valid IPv4 address with prefix length

string value = 1 [(buf.validate.field).string.ipv4_with_prefixlen = true];

TimestampRules

特定の日時と完全に一致させたいとき

value must equal 2023-05-03T10:00:00Z

google.protobuf.Timestamp created_at = 1 [
  (buf.validate.field).timestamp.const = { seconds: 1683108000 }
];

指定した日時より前でなければならないとき

value must be less than 2023-05-14T00:00:00Z

google.protobuf.Timestamp deadline = 1 [
  (buf.validate.field).timestamp.lt = { seconds: 1684003200 }
];

指定した日時以前でなければならないとき

value must be less than or equal to 2023-05-14T00:00:00Z

google.protobuf.Timestamp deadline = 1 [
  (buf.validate.field).timestamp.lte = { seconds: 1684003200 }
];

現在時刻より前でなければならないとき

value must be less than now

google.protobuf.Timestamp created_at = 1 [
  (buf.validate.field).timestamp.lt_now = true
];

指定した日時より後でなければならないとき

value must be greater than 2023-01-01T00:00:00Z

google.protobuf.Timestamp started_at = 1 [
  (buf.validate.field).timestamp.gt = { seconds: 1672531200 }
];

指定した日時以降でなければならないとき

value must be greater than or equal to 2023-01-01T00:00:00Z

google.protobuf.Timestamp started_at = 1 [
  (buf.validate.field).timestamp.gte = { seconds: 1672531200 }
];

現在時刻より後でなければならないとき

value must be greater than now

google.protobuf.Timestamp expires_at = 1 [
  (buf.validate.field).timestamp.gt_now = true
];

現在時刻 ± 指定時間内にある必要があるとき

value must be within 1 hour of now

google.protobuf.Timestamp scheduled_at = 1 [
  (buf.validate.field).timestamp.within = { seconds: 3600 }
];

範囲指定(例:開始日時より後、終了日時より前)

value must be greater than 2023-01-01T00:00:00Z and less than 2023-01-02T00:00:00Z

google.protobuf.Timestamp meeting_time = 1 [
  (buf.validate.field).timestamp = {
    gt: { seconds: 1672531200 },
    lt: { seconds: 1672617600 }
  }
];

まとめ

いかがでしたでしょうか😊!

本記事では protovalidate の基本的な逆引きリファレンスをご紹介しました。

次回は、ignore や oneof など、より実践的で応用的な内容についても触れていければと思っています!
ぜひ引き続きチェックしていただけると嬉しいです〜!

株式会社BALEEN STUDIO

Discussion