quarks-tech / protoc-gen-validate
PHP 的 proto 验证库
Requires
- php: >=5.5.0
- google/protobuf: ^3.6.1
Requires (Dev)
- phpunit/phpunit: >=4.8.0
Suggests
- ext-bcmath: Need to support JSON deserialization
This package is not auto-updated.
Last update: 2022-05-18 14:51:49 UTC
README
该项目目前处于 alpha 阶段。API 应被视为不稳定且可能会更改
PGV 是一个 protoc 插件,用于生成多语言消息验证器。虽然协议缓冲区有效地保证了结构化数据类型,但它们无法强制执行值语义规则。此插件为 protoc 生成的代码添加了对这些约束的支持。
开发者导入 PGV 扩展,并在他们的 proto 文件中用约束规则注释消息和字段
syntax = "proto3"; package examplepb; import "validate/validate.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 = { pattern: "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$", max_bytes: 256, }]; Location home = 4 [(validate.rules).message.required = true]; message Location { double lat = 1 [(validate.rules).double = { gte: -90, lte: 90 }]; double lng = 2 [(validate.rules).double = { gte: -180, lte: 180 }]; } }
使用 PGV 和目标语言的默认插件执行 protoc
将在生成的类型上创建 Validate
方法
p := new(Person) err := p.Validate() // err: Id must be greater than 999 p.Id = 1000 err = p.Validate() // err: Email must be a valid email address p.Email = "example@lyft.com" err = p.Validate() // err: Name must match pattern '^[^\d\s]+( [^\d\s]+)*$' p.Name = "Protocol Buffer" err = p.Validate() // err: Home is required p.Home = &Location{37.7, 999} err = p.Validate() // err: Home.Lng must be within [-180, 180] p.Home.Lng = -122.4 err = p.Validate() // err: nil
用法
依赖
go
工具链(≥ v1.7)protoc
编译器在$PATH
中protoc-gen-validate
在$PATH
中- 针对目标语言(s)的官方语言特定插件
- 目前仅支持
proto3
语法。 计划支持proto2
语法。
安装
目前只能从源代码安装 PGV
# fetches this repo into $GOPATH go get -d github.com/envoyproxy/protoc-gen-validate # installs PGV into $GOPATH/bin make build
参数
lang
: 指定要生成的目标语言。目前,唯一支持的选项是go
cc
for c++(部分实现)java
- 注意:Python 通过运行时代码生成工作。没有编译时生成。有关详细信息,请参阅 Python 部分。
示例
Go
Go 生成应发生在与官方插件相同的输出路径中。对于 proto 文件 example.proto
,相应的验证代码生成到 ../generated/example.pb.validate.go
protoc \ -I . \ -I ${GOPATH}/src \ -I ${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate \ --go_out=":../generated" \ --validate_out="lang=go:../generated" \ example.proto
所有生成的消息都包含以下方法
Validate() error
返回验证期间遇到的第一个错误。ValidateAll() error
返回验证期间遇到的全部错误。
PGV 对现有生成的代码不需要任何额外的运行时依赖。
注意:默认情况下,example.pb.validate.go 是嵌套在与您的 option go_package
名称匹配的目录结构中的。您可以使用 protoc 参数 paths=source_relative:.
来更改此结构。然后,--validate_out
将输出到预期的文件。有关更多信息,请参阅 Google 的 protobuf 文档或 packages and input paths 或 parameters。
还支持 module=example.com/foo
标志 此处 描述。
Java
Java 生成与现有的 protobuf 工具链集成到 java 项目中。对于 Maven 项目,请在 pom.xml 或 build.gradle 中添加以下内容。
<dependencies> <dependency> <groupId> io.envoyproxy.protoc-gen-validate</groupId> <artifactId>pgv-java-stub</artifactId> <version>${pgv.version}</version> </dependency> </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.4.1.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact> </configuration> <executions> <execution> <id>protoc-java-pgv</id> <goals> <goal>compile-custom</goal> </goals> <configuration> <pluginParameter>lang=java</pluginParameter> <pluginId>java-pgv</pluginId> <pluginArtifact>io.envoyproxy.protoc-gen-validate:protoc-gen-validate:${pgv.version}:exe:${os.detected.classifier}</pluginArtifact> </configuration> </execution> </executions> </plugin> </plugins> </build>
plugins { ... id "com.google.protobuf" version "${protobuf.version}" ... } protobuf { protoc { artifact = "com.google.protobuf:protoc:${protoc.version}" } plugins { javapgv { artifact = "io.envoyproxy.protoc-gen-validate:protoc-gen-validate:${pgv.version}" } } generateProtoTasks { all()*.plugins { javapgv { option "lang=java" } } } }
// Create a validator index that reflectively loads generated validators ValidatorIndex index = new ReflectiveValidatorIndex(); // Assert that a message is valid index.validatorFor(message.getClass()).assertValid(message); // Create a gRPC client and server interceptor to automatically validate messages (requires pgv-java-grpc module) clientStub = clientStub.withInterceptors(new ValidatingClientInterceptor(index)); serverBuilder.addService(ServerInterceptors.intercept(svc, new ValidatingServerInterceptor(index)));
Python
Python实现通过即时编译(JIT)代码生成。换句话说,validate(msg)
函数是按需编写的,并通过exec-ed执行。通过存储每个描述符生成的函数,LRU缓存提高了性能。
Python包可在PyPI上找到。
要运行validate()
,请执行以下操作
from entities_pb2 import Person from protoc_gen_validate.validator import validate, ValidationFailed p = Person(first_name="Foo", last_name="Bar", age=42) try: validate(p) except ValidationFailed as err: print(err)
您可以使用print_validate()
函数查看已生成的代码。
约束规则
提供的约束主要模仿JSON Schema中的约束。PGV规则可以混合用于同一字段;插件确保在代码生成前应用于字段的规则不能相互矛盾。
查看约束规则比较矩阵以了解特定语言约束功能。
数值
所有数值类型(
float
、double
、int32
、int64
、uint32
、uint64
、sint32
、sint64
、fixed32
、fixed64
、sfixed32
、sfixed64
)共享相同的规则。
-
const:字段必须严格等于指定的值。
// x must equal 1.23 exactly float x = 1 [(validate.rules).float.const = 1.23];
-
lt/lte/gt/gte:这些不等式(分别为
<
、<=
、>
、>=
)允许推导出字段必须存在的范围。// x must be less than 10 int32 x = 1 [(validate.rules).int32.lt = 10]; // x must be greater than or equal to 20 uint64 x = 1 [(validate.rules).uint64.gte = 20]; // x must be in the range [30, 40) fixed32 x = 1 [(validate.rules).fixed32 = {gte:30, lt: 40}];
反转
lt(e)
和gt(e)
的值是有效的,并创建一个排他性范围。// x must be outside the range [30, 40) double x = 1 [(validate.rules).double = {lt:30, gte:40}];
-
in/not_in:这两个规则允许指定字段的值允许/拒绝列表。
// x must be either 1, 2, or 3 uint32 x = 1 [(validate.rules).uint32 = {in: [1,2,3]}]; // x cannot be 0 nor 0.99 float x = 1 [(validate.rules).float = {not_in: [0, 0.99]}];
-
ignore_empty:此规则指定如果字段为空或设置为默认值,则忽略任何验证规则。这些通常在可以在更新请求中取消设置字段或跳过验证可选字段(在这种情况下无法切换到WKTs)时很有用。
unint32 x = 1 [(validate.rules).uint32 = {ignore_empty: true, gte: 200}];
布尔值
-
const:字段必须严格等于指定的值。
// x must be set to true bool x = 1 [(validate.rules).bool.const = true]; // x cannot be set to true bool x = 1 [(validate.rules).bool.const = false];
字符串
-
const:字段必须严格等于指定的值。
// x must be set to "foo" string x = 1 [(validate.rules).string.const = "foo"];
-
len/min_len/max_len:这些规则限制了字段中的字符数(Unicode代码点数)。请注意,字符数可能与字符串中的字节数不同。字符串按原样考虑,不进行规范化。
// x must be exactly 5 characters long string x = 1 [(validate.rules).string.len = 5]; // x must be at least 3 characters long string x = 1 [(validate.rules).string.min_len = 3]; // x must be between 5 and 10 characters, inclusive string x = 1 [(validate.rules).string = {min_len: 5, max_len: 10}];
-
min_bytes/max_bytes:这些规则限制了字段中的字节数。
// x must be at most 15 bytes long string x = 1 [(validate.rules).string.max_bytes = 15]; // x must be between 128 and 1024 bytes long string x = 1 [(validate.rules).string = {min_bytes: 128, max_bytes: 1024}];
-
pattern:字段必须匹配指定的RE2兼容正则表达式。包含的表达式应省略任何分隔符(例如,
/\d+/
应仅是\d+
)。// x must be a non-empty, case-insensitive hexadecimal string string x = 1 [(validate.rules).string.pattern = "(?i)^[0-9a-f]+$"];
-
prefix/suffix/contains/not_contains:字段必须包含指定的子串,或在可选的显式位置中不包含指定的子串。
// x must begin with "foo" string x = 1 [(validate.rules).string.prefix = "foo"]; // x must end with "bar" string x = 1 [(validate.rules).string.suffix = "bar"]; // x must contain "baz" anywhere inside it string x = 1 [(validate.rules).string.contains = "baz"]; // x cannot contain "baz" anywhere inside it string x = 1 [(validate.rules).string.not_contains = "baz"]; // x must begin with "fizz" and end with "buzz" string x = 1 [(validate.rules).string = {prefix: "fizz", suffix: "buzz"}]; // x must end with ".proto" and be less than 64 characters string x = 1 [(validate.rules).string = {suffix: ".proto", max_len:64}];
-
in/not_in:这两个规则允许指定字段的值允许/拒绝列表。
// x must be either "foo", "bar", or "baz" string x = 1 [(validate.rules).string = {in: ["foo", "bar", "baz"]}]; // x cannot be "fizz" nor "buzz" string x = 1 [(validate.rules).string = {not_in: ["fizz", "buzz"]}];
-
ignore_empty:此规则指定如果字段为空或设置为默认值,则忽略任何验证规则。这些通常在可以在更新请求中取消设置字段或跳过验证可选字段(在这种情况下无法切换到WKTs)时很有用。
string CountryCode = 1 [(validate.rules).string = {ignore_empty: true, len: 2}];
-
well-known formats:这些规则为常见的字符串模式提供高级约束。这些约束通常比等效的正则表达式模式更宽松且性能更好,同时提供更详细的失败描述。
// x must be a valid email address (via RFC 1034) string x = 1 [(validate.rules).string.email = true]; // x must be a valid address (IP or Hostname). string x = 1 [(validate.rules).string.address = true]; // x must be a valid hostname (via RFC 1034) string x = 1 [(validate.rules).string.hostname = true]; // x must be a valid IP address (either v4 or v6) string x = 1 [(validate.rules).string.ip = true]; // x must be a valid IPv4 address // eg: "192.168.0.1" string x = 1 [(validate.rules).string.ipv4 = true]; // x must be a valid IPv6 address // eg: "fe80::3" string x = 1 [(validate.rules).string.ipv6 = true]; // x must be a valid absolute URI (via RFC 3986) string x = 1 [(validate.rules).string.uri = true]; // x must be a valid URI reference (either absolute or relative) string x = 1 [(validate.rules).string.uri_ref = true]; // x must be a valid UUID (via RFC 4122) string x = 1 [(validate.rules).string.uuid = true]; // x must conform to a well known regex for HTTP header names (via RFC 7230) string x = 1 [(validate.rules).string.well_known_regex = HTTP_HEADER_NAME] // x must conform to a well known regex for HTTP header values (via RFC 7230) string x = 1 [(validate.rules).string.well_known_regex = HTTP_HEADER_VALUE]; // x must conform to a well known regex for headers, disallowing \r\n\0 characters. string x = 1 [(validate.rules).string {well_known_regex: HTTP_HEADER_VALUE, strict: false}];
字节
应使用字符串表示字面值,在必要时使用转义。
-
const:字段必须严格等于指定的值。
// x must be set to "foo" ("\x66\x6f\x6f") bytes x = 1 [(validate.rules).bytes.const = "foo"]; // x must be set to "\xf0\x90\x28\xbc" bytes x = 1 [(validate.rules).bytes.const = "\xf0\x90\x28\xbc"];
-
len/min_len/max_len:这些规则限制了字段中的字节数。
// x must be exactly 3 bytes bytes x = 1 [(validate.rules).bytes.len = 3]; // x must be at least 3 bytes long bytes x = 1 [(validate.rules).bytes.min_len = 3]; // x must be between 5 and 10 bytes, inclusive bytes x = 1 [(validate.rules).bytes = {min_len: 5, max_len: 10}];
-
pattern:字段必须匹配指定的RE2兼容正则表达式。包含的表达式应省略任何分隔符(例如,
/\d+/
应仅是\d+
)。// x must be a non-empty, ASCII byte sequence bytes x = 1 [(validate.rules).bytes.pattern = "^[\x00-\x7F]+$"];
-
prefix/suffix/contains:字段必须包含指定的字节序列,或在可选的显式位置中包含。
// x must begin with "\x99" bytes x = 1 [(validate.rules).bytes.prefix = "\x99"]; // x must end with "buz\x7a" bytes x = 1 [(validate.rules).bytes.suffix = "buz\x7a"]; // x must contain "baz" anywhere inside it bytes x = 1 [(validate.rules).bytes.contains = "baz"];
-
in/not_in:这两个规则允许指定字段的值允许/拒绝列表。
// x must be either "foo", "bar", or "baz" bytes x = 1 [(validate.rules).bytes = {in: ["foo", "bar", "baz"]}]; // x cannot be "fizz" nor "buzz" bytes x = 1 [(validate.rules).bytes = {not_in: ["fizz", "buzz"]}];
-
ignore_empty:此规则指定如果字段为空或设置为默认值,则忽略任何验证规则。这些通常在可以在更新请求中取消设置字段或跳过验证可选字段(在这种情况下无法切换到WKTs)时很有用。
bytes x = 1 [(validate.rules).bytes = {ignore_empty: true, in: ["foo", "bar", "baz"]}];
-
常用格式:这些规则为常见模式提供了高级约束。这些约束通常比等效的正则表达式模式更为宽容和高效,同时提供更详细的失败描述。
// x must be a valid IP address (either v4 or v6) in byte format bytes x = 1 [(validate.rules).bytes.ip = true]; // x must be a valid IPv4 address in byte format // eg: "\xC0\xA8\x00\x01" bytes x = 1 [(validate.rules).bytes.ipv4 = true]; // x must be a valid IPv6 address in byte format // eg: "\x20\x01\x0D\xB8\x85\xA3\x00\x00\x00\x00\x8A\x2E\x03\x70\x73\x34" bytes x = 1 [(validate.rules).bytes.ipv6 = true];
枚举
所有字面值都应该使用枚举描述符中定义的数值(int32)。
以下示例使用了此 State
枚举
enum State { INACTIVE = 0; PENDING = 1; ACTIVE = 2; }
-
const:字段必须严格等于指定的值。
// x must be set to ACTIVE (2) State x = 1 [(validate.rules).enum.const = 2];
-
仅定义:字段必须是枚举描述符中指定的值之一。
// x can only be INACTIVE, PENDING, or ACTIVE State x = 1 [(validate.rules).enum.defined_only = true];
-
in/not_in:这两个规则允许指定字段的值允许/拒绝列表。
// x must be either INACTIVE (0) or ACTIVE (2) State x = 1 [(validate.rules).enum = {in: [0,2]}]; // x cannot be PENDING (1) State x = 1 [(validate.rules).enum = {not_in: [1]}];
消息
如果一个字段包含消息,并且该消息是由 PGV 生成的,则将递归地进行验证。未使用 PGV 生成的消息将被跳过。
// if Person was generated with PGV and x is set, // x's fields will be validated. Person x = 1;
-
跳过:此规则指定不应评估此字段的验证规则。
// The fields on Person x will not be validated. Person x = 1 [(validate.rules).message.skip = true];
-
必需:此规则指定字段不能被清除。
// x cannot be unset Person x = 1 [(validate.rules).message.required = true]; // x cannot be unset, but the validations on x will not be performed Person x = 1 [(validate.rules).message = {required: true, skip: true}];
重复
-
min_items/max_items:这些规则控制字段中包含的元素数量
// x must contain at least 3 elements repeated int32 x = 1 [(validate.rules).repeated.min_items = 3]; // x must contain between 5 and 10 Persons, inclusive repeated Person x = 1 [(validate.rules).repeated = {min_items: 5, max_items: 10}]; // x must contain exactly 7 elements repeated double x = 1 [(validate.rules).repeated = {min_items: 7, max_items: 7}];
-
唯一:此规则要求字段中的所有元素必须是唯一的。此规则不支持重复的消息。
// x must contain unique int64 values repeated int64 x = 1 [(validate.rules).repeated.unique = true];
-
items:此规则指定应用于字段中每个元素的约束。重复消息字段也应用其验证规则,除非在此约束中指定了
skip
。// x must contain positive float values repeated float x = 1 [(validate.rules).repeated.items.float.gt = 0]; // x must contain Persons but don't validate them repeated Person x = 1 [(validate.rules).repeated.items.message.skip = true];
-
ignore_empty:此规则指定如果字段为空或设置为默认值,则忽略任何验证规则。这些通常在可以在更新请求中取消设置字段或跳过验证可选字段(在这种情况下无法切换到WKTs)时很有用。
repeated int64 x = 1 [(validate.rules).repeated = {ignore_empty: true, items: {int64: {gt: 200}}}];
映射
-
min_pairs/max_pairs:这些规则控制此字段中包含的键值对数量
// x must contain at most 3 KV pairs map<string, uint64> x = 1 [(validate.rules).map.min_pairs = 3]; // x must contain between 5 and 10 KV pairs map<string, string> x = 1 [(validate.rules)].map = {min_pairs: 5, max_pairs: 10}]; // x must contain exactly 7 KV pairs map<string, Person> x = 1 [(validate.rules)].map = {min_pairs: 7, max_pairs: 7}];
-
no_sparse:对于具有消息值的映射字段,将此规则设置为 true 将不允许具有未设置值的键。
// all values in x must be set map<uint64, Person> x = 1 [(validate.rules).map.no_sparse = true];
-
keys:此规则指定应用于字段中键的约束。
// x's keys must all be negative <sint32, string> x = [(validate.rules).map.keys.sint32.lt = 0];
-
values:此规则指定应用于字段中每个值的约束。重复消息字段也应用其验证规则,除非在此约束中指定了
skip
。// x must contain strings of at least 3 characters map<string, string> x = 1 [(validate.rules).map.values.string.min_len = 3]; // x must contain Persons but doesn't validate them map<string, Person> x = 1 [(validate.rules).map.values.message.skip = true];
-
ignore_empty:此规则指定如果字段为空或设置为默认值,则忽略任何验证规则。这些通常在可以在更新请求中取消设置字段或跳过验证可选字段(在这种情况下无法切换到WKTs)时很有用。
map<string, string> x = 1 [(validate.rules).map = {ignore_empty: true, values: {string: {min_len: 3}}}];
已知类型(WKTs)
一组 WKTs 随 protoc 包装,并包含许多领域中有用的常见消息模式。
标量值包装器
在 proto3
语法中,无法区分未设置和标量字段的零值。值 WKTs 通过将它们包装在消息中允许这种区分。PGV 允许使用包装器封装的相同标量规则。
// if it is set, x must be greater than 3
google.protobuf.Int32Value x = 1 [(validate.rules).int32.gt = 3];
消息规则也可以与标量已知类型(WKTs)一起使用
// Ensures that if a value is not set for age, it would not pass the validation despite its zero value being 0. message X { google.protobuf.Int32Value age = 1 [(validate.rules).int32.gt = -1, (validate.rules).message.required = true]; }
任意的
-
必需:此规则指定字段必须被设置
// x cannot be unset google.protobuf.Any x = 1 [(validate.rules).any.required = true];
-
in/not_in:这两个规则允许指定此字段中
type_url
值的允许/拒绝列表。如果可能,考虑使用oneof
联合代替in
。// x must not be the Duration or Timestamp WKT google.protobuf.Any x = 1 [(validate.rules).any = {not_in: [ "type.googleapis.com/google.protobuf.Duration", "type.googleapis.com/google.protobuf.Timestamp" ]}];
持续时间
-
必需:此规则指定字段必须被设置
// x cannot be unset google.protobuf.Duration x = 1 [(validate.rules).duration.required = true];
-
const:字段必须严格等于指定的值。
// x must equal 1.5s exactly google.protobuf.Duration x = 1 [(validate.rules).duration.const = { seconds: 1, nanos: 500000000 }];
-
lt/lte/gt/gte:这些不等式(分别为
<
、<=
、>
、>=
)允许推导出字段必须存在的范围。// x must be less than 10s google.protobuf.Duration x = 1 [(validate.rules).duration.lt.seconds = 10]; // x must be greater than or equal to 20ns google.protobuf.Duration x = 1 [(validate.rules).duration.gte.nanos = 20]; // x must be in the range [0s, 1s) google.protobuf.Duration x = 1 [(validate.rules).duration = { gte: {}, lt: {seconds: 1} }];
反转
lt(e)
和gt(e)
的值是有效的,并创建一个排他性范围。// x must be outside the range [0s, 1s) google.protobuf.Duration x = 1 [(validate.rules).duration = { lt: {}, gte: {seconds: 1} }];
-
in/not_in:这两个规则允许指定字段的值允许/拒绝列表。
// x must be either 0s or 1s google.protobuf.Duration x = 1 [(validate.rules).duration = {in: [ {}, {seconds: 1} ]}]; // x cannot be 20s nor 500ns google.protobuf.Duration x = 1 [(validate.rules).duration = {not_in: [ {seconds: 20}, {nanos: 500} ]}];
时间戳
-
必需:此规则指定字段必须被设置
// x cannot be unset google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.required = true];
-
const:字段必须严格等于指定的值。
// x must equal 2009/11/10T23:00:00.500Z exactly google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.const = { seconds: 63393490800, nanos: 500000000 }];
-
lt/lte/gt/gte:这些不等式(分别为
<
、<=
、>
、>=
)允许推导出字段必须存在的范围。// x must be less than the Unix Epoch google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.lt.seconds = 0]; // x must be greater than or equal to 2009/11/10T23:00:00Z google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.gte.seconds = 63393490800]; // x must be in the range [epoch, 2009/11/10T23:00:00Z) google.protobuf.Timestamp x = 1 [(validate.rules).timestamp = { gte: {}, lt: {seconds: 63393490800} }];
反转
lt(e)
和gt(e)
的值是有效的,并创建一个排他性范围。// x must be outside the range [epoch, 2009/11/10T23:00:00Z) google.protobuf.Timestamp x = 1 [(validate.rules).timestamp = { lt: {}, gte: {seconds: 63393490800} }];
-
lt_now/gt_now:这些不等式允许相对于当前时间的范围。这些规则不能与上面的绝对规则一起使用。
// x must be less than the current timestamp google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.lt_now = true];
-
within:此规则指定字段值应在当前时间范围内。此规则可与
lt_now
和gt_now
一起使用,以控制这些范围。// x must be within ±1s of the current time google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.within.seconds = 1]; // x must be within the range (now, now+1h) google.protobuf.Timestamp x = 1 [(validate.rules).timestamp = { gt_now: true, within: {seconds: 3600} }];
消息-全局
-
禁用:可以取消消息中所有字段的验证规则,包括支持自身验证的消息字段。
message Person { option (validate.disabled) = true; // x will not be required to be greater than 123 uint64 x = 1 [(validate.rules).uint64.gt = 123]; // y's fields will not be validated Person y = 2; }
-
忽略:不为此消息生成验证方法或任何相关验证代码。
message Person { option (validate.ignored) = true; // x will not be required to be greater than 123 uint64 x = 1 [(validate.rules).uint64.gt = 123]; // y's fields will not be validated Person y = 2; }
OneOfs
-
必需:要求
oneof
中的一个字段必须设置。默认情况下,联合字段可以是空的或其中一个被设置。启用此规则将不允许所有字段都不设置。oneof id { // either x, y, or z must be set. option (validate.required) = true; string x = 1; int32 y = 2; Person z = 3; }
开发
PGV是在protoc-gen-star框架之上用Go编写的,并编译为独立的二进制文件。
依赖项
所有PGV依赖项目前都已提交到项目中。要测试PGV,必须安装protoc
,可以从源代码、提供的发布版本或包管理器安装。还应该安装目标语言的官方protoc插件。
Make 目标
-
make build
:生成约束proto并将其编译到$GOPATH/bin
-
make lint
:对PGV代码库运行静态分析规则,包括golint
、go vet
和gofmt -s
-
make testcases
:在/tests/harness/cases
中生成proto文件。这些文件由测试框架用于验证为每种语言生成的验证规则。 -
make harness
:针对每种语言的测试框架执行测试用例。
在Bazel下运行所有测试
确保您的PATH
已设置以包括protoc-gen-go
和protoc
,然后
bazel test //tests/...
Docker
PGV附带一个Dockerfile,用于一致的开发工具和CI。主要入口点是带有默认目标的make
。此存储库应挂载到/go/src/github.com/envoyproxy/protoc-gen-validate
以正确运行。
# build the image docker build -t lyft/protoc-gen-validate . # executes the default make target: quick docker run --rm \ -v $(PWD):/go/src/github.com/envoyproxy/protoc-gen-validate \ lyft/protoc-gen-validate # executes the 'build' & 'generate-testdata' make targets docker run --rm \ -v $(PWD):/go/src/github.com/envoyproxy/protoc-gen-validate \ lyft/protoc-gen-validate \ build generate-testdata