# protoc-gen-validate
**Repository Path**: github-fast-sync/protoc-gen-validate
## Basic Information
- **Project Name**: protoc-gen-validate
- **Description**: 同步github仓库
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-11-16
- **Last Updated**: 2022-11-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README

# protoc-gen-validate (PGV)



*This project is currently in **alpha**. The API should be considered unstable
and likely to change*
PGV is a protoc plugin to generate polyglot message validators. While protocol
buffers effectively guarantee the types of structured data, they cannot enforce
semantic rules for values. This plugin adds support to protoc-generated code to
validate such constraints.
Developers import the PGV extension and annotate the messages and fields in
their proto files with constraint rules:
```protobuf
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}];
  }
}
```
Executing `protoc` with PGV and the target language's default plugin will
create `Validate` methods on the generated types:
```go
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@bufbuild.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
```
## Usage
### Dependencies
- `go` toolchain (≥ v1.7)
- `protoc` compiler in `$PATH`
- `protoc-gen-validate` in `$PATH`
- official language-specific plugin for target language(s)
- **Only `proto3` syntax is currently supported.** `proto2` syntax support is
  planned.
### Installation
Installing PGV can currently only be done from source:
```sh
# fetches this repo into $GOPATH
go get -d github.com/envoyproxy/protoc-gen-validate
```
> #### 💡 Yes, our go module path is `github.com/envoyproxy/protoc-gen-validate` **not** `bufbuild` this is intentional.
> Changing the module path is effectively creating a new, independent module. We
> would prefer not to break our users. The Go team are working on
> better `cmd/go`
> support for modules that change paths, but progress is slow. Until then, we
> will
> continue to use the `bufbuild` module path.
```
git clone github.com/bufbuild/protoc-gen-validate
# installs PGV into $GOPATH/bin
cd protoc-gen-validate && make build
```
### Parameters
- **`lang`**: specify the target language to generate. Currently, the only
  supported options are:
    - `go`
    - `cc` for c++ (partially implemented)
    - `java`
- Note: Python works via runtime code generation. There's no compile-time
  generation. See the Python section for details.
### Examples
#### Go
Go generation should occur into the same output path as the official plugin. For
a proto file `example.proto`, the corresponding validation code is generated
into `../generated/example.pb.validate.go`:
```sh
protoc \
  -I . \
  -I path/to/validate/ \ 
  --go_out=":../generated" \
  --validate_out="lang=go:../generated" \
  example.proto
```
All messages generated include the following methods:
- `Validate() error` which returns the first error encountered during
  validation.
- `ValidateAll() error` which returns all errors encountered during validation.
PGV requires no additional runtime dependencies from the existing generated
code.
**Note**: by default **example.pb.validate.go** is nested in a directory
structure that matches your `option go_package` name. You can change this using
the protoc parameter `paths=source_relative:.`. Then `--validate_out` will
output the file where it is expected. See Google's protobuf documentation
or [packages and input paths](https://github.com/golang/protobuf#packages-and-input-paths)
or [parameters](https://github.com/golang/protobuf#parameters) for more
information.
There's also support for the `module=example.com/foo`
flag [described here](https://developers.google.com/protocol-buffers/docs/reference/go-generated#invocation)
.
#### Java
Java generation is integrated with the existing protobuf toolchain for java
projects. For Maven projects, add the
following to your pom.xml or build.gradle.
```xml
    
        build.buf.protoc-gen-validate
        pgv-java-stub
        ${pgv.version}
    
    
        kr.motd.maven
        os-maven-plugin
        1.4.1.Final
    
    
        org.xolstice.maven.plugins
        protobuf-maven-plugin
        0.6.1
        
            
                com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
            
        
        
            
                protoc-java-pgv
                
                    compile-custom
                
                
                    lang=java
                    java-pgv
                    
                        build.buf.protoc-gen-validate:protoc-gen-validate:${pgv.version}:exe:${os.detected.classifier}
                    
                
            
        
    
```
```gradle
plugins {
    ...
    id "com.google.protobuf" version "${protobuf.version}"
    ...
}
protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:${protoc.version}"
    }
    plugins {
        javapgv {
            artifact = "build.buf.protoc-gen-validate:protoc-gen-validate:${pgv.version}"
        }
    }
    generateProtoTasks {
        all()*.plugins {
            javapgv {
                option "lang=java"
            }
        }
    }
}
```
```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
The python implementation works via JIT code generation. In other words,
the `validate(msg)` function is written
on-demand and [exec-ed](https://docs.python.org/3/library/functions.html#exec).
An LRU-cache improves performance by
storing generated functions per descriptor.
The python package is available
on [PyPI](https://pypi.org/project/protoc-gen-validate).
To run `validate()`, do the following:
```python
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)
```
You can view what code has been generated by using the `print_validate()`
function.
## Constraint Rules
[The provided constraints](validate/validate.proto) are modeled largerly after
those in JSON Schema. PGV rules can be mixed for the same field; the plugin
ensures the rules applied to a field cannot contradict before code generation.
Check the [constraint rule comparison matrix](rule_comparison.md) for
language-specific constraint capabilities.
### Numerics
> All numeric types (`float`, `double`, `int32`, `int64`, `uint32`, `uint64`
> , `sint32`, `sint64`, `fixed32`, `fixed64`, `sfixed32`, `sfixed64`) share the
> same rules.
- **const**: the field must be _exactly_ the specified value.
  ```protobuf
  // x must equal 1.23 exactly
  float x = 1 [(validate.rules).float.const = 1.23];
  ```
- **lt/lte/gt/gte**: these inequalities (`<`, `<=`, `>`, `>=`, respectively)
  allow for deriving ranges in which the field must reside.
  ```protobuf
  // 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}];
  ```
  Inverting the values of `lt(e)` and `gt(e)` is valid and creates an exclusive
  range.
  ```protobuf
  // x must be outside the range [30, 40)
  double x = 1 [(validate.rules).double = {lt:30, gte:40}];
  ```
- **in/not_in**: these two rules permit specifying allow/denylists for the
  values of a field.
  ```protobuf
  // 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**: this rule specifies that if field is empty or set to the
  default value, to ignore any validation rules. These are typically useful
  where being able to unset a field in an update request, or to skip validation
  for optional fields where switching to WKTs is not feasible.
  ```protobuf
  unint32 x = 1 [(validate.rules).uint32 = {ignore_empty: true, gte: 200}];
  ```
### Bools
- **const**: the field must be _exactly_ the specified value.
  ```protobuf
  // 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];
  ```
### Strings
- **const**: the field must be _exactly_ the specified value.
  ```protobuf
  // x must be set to "foo"
  string x = 1 [(validate.rules).string.const = "foo"];
  ```
- **len/min_len/max_len**: these rules constrain the number of characters (
  Unicode code points) in the field. Note that the number of characters may
  differ from the number of bytes in the string. The string is considered as-is,
  and does not normalize.
  ```protobuf
  // 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**: these rules constrain the number of bytes in the
  field.
  ```protobuf
  // 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**: the field must match the specified [RE2-compliant][re2] regular
  expression. The included expression should elide any delimiters (ie, `/\d+/`
  should just be `\d+`).
  ```protobuf
  // 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**: the field must contain the specified
  substring in an optionally explicit location, or not contain the specified
  substring.
  ```protobuf
  // 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**: these two rules permit specifying allow/denylists for the
  values of a field.
  ```protobuf
  // 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**: this rule specifies that if field is empty or set to the
  default value, to ignore any validation rules. These are typically useful
  where being able to unset a field in an update request, or to skip validation
  for optional fields where switching to WKTs is not feasible.
  ```protobuf
  string CountryCode = 1 [(validate.rules).string = {ignore_empty: true, len: 2}];
  ```
- **well-known formats**: these rules provide advanced constraints for common
  string patterns. These constraints will typically be more permissive and
  performant than equivalent regular expression patterns, while providing more
  explanatory failure descriptions.
  ```protobuf
  // x must be a valid email address (via RFC 5322)
  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}];
  ```
### Bytes
> Literal values should be expressed with strings, using escaping where
> necessary.
- **const**: the field must be _exactly_ the specified value.
  ```protobuf
  // 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**: these rules constrain the number of bytes in the
  field.
  ```protobuf
  // 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**: the field must match the specified [RE2-compliant][re2] regular
  expression. The included expression should elide any delimiters (ie, `/\d+/`
  should just be `\d+`).
  ```protobuf
  // x must be a non-empty, ASCII byte sequence
  bytes x = 1 [(validate.rules).bytes.pattern = "^[\x00-\x7F]+$"];
  ```
- **prefix/suffix/contains**: the field must contain the specified byte sequence
  in an optionally explicit location.
  ```protobuf
  // 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**: these two rules permit specifying allow/denylists for the
  values of a field.
  ```protobuf
  // 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**: this rule specifies that if field is empty or set to the
  default value, to ignore any validation rules. These are typically useful
  where being able to unset a field in an update request, or to skip validation
  for optional fields where switching to WKTs is not feasible.
  ```protobuf
  bytes x = 1 [(validate.rules).bytes = {ignore_empty: true, in: ["foo", "bar", "baz"]}];
  ```
- **well-known formats**: these rules provide advanced constraints for common
  patterns. These constraints will typically be more permissive and performant
  than equivalent regular expression patterns, while providing more explanatory
  failure descriptions.
  ```protobuf
  // 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];
  ```
### Enums
> All literal values should use the numeric (int32) value as defined in the enum
> descriptor.
The following examples use this `State` enum
```protobuf
enum State {
  INACTIVE = 0;
  PENDING = 1;
  ACTIVE = 2;
}
```
- **const**: the field must be _exactly_ the specified value.
  ```protobuf
  // x must be set to ACTIVE (2)
  State x = 1 [(validate.rules).enum.const = 2];
  ```
- **defined_only**: the field must be one of the specified values in the enum
  descriptor.
  ```protobuf
  // x can only be INACTIVE, PENDING, or ACTIVE
  State x = 1 [(validate.rules).enum.defined_only = true];
  ```
- **in/not_in**: these two rules permit specifying allow/denylists for the
  values of a field.
  ```protobuf
  // 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]}];
  ```
### Messages
> If a field contains a message and the message has been generated with PGV,
> validation will be performed recursively. Message's not generated with PGV are
> skipped.
```protobuf
// if Person was generated with PGV and x is set,
// x's fields will be validated.
    Person x = 1;
```
- **skip**: this rule specifies that the validation rules of this field should
  not be evaluated.
  ```protobuf
  // The fields on Person x will not be validated.
  Person x = 1 [(validate.rules).message.skip = true];
  ```
- **required**: this rule specifies that the field cannot be unset.
  ```protobuf
  // 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}];
  ```
### Repeated
- **min_items/max_items**: these rules control how many elements are contained
  in the field
  ```protobuf
  // 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}];
  ```
- **unique**: this rule requires that all elements in the field must be unique.
  This rule does not support repeated messages.
  ```protobuf
  // x must contain unique int64 values
  repeated int64 x = 1 [(validate.rules).repeated.unique = true];
  ```
- **items**: this rule specifies constraints that should be applied to each
  element in the field. Repeated message fields also have their validation rules
  applied unless `skip` is specified on this constraint.
  ```protobuf
  // 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**: this rule specifies that if field is empty or set to the
  default value, to ignore any validation rules. These are typically useful
  where being able to unset a field in an update request, or to skip validation
  for optional fields where switching to WKTs is not feasible.
  ```protobuf
  repeated int64 x = 1 [(validate.rules).repeated = {ignore_empty: true, items: {int64: {gt: 200}}}];
  ```
### Maps
- **min_pairs/max_pairs**: these rules control how many KV pairs are contained
  in this field
  ```protobuf
  // x must contain at least 3 KV pairs
  map x = 1 [(validate.rules).map.min_pairs = 3];
  // x must contain between 5 and 10 KV pairs
  map x = 1 [(validate.rules).map = {min_pairs: 5, max_pairs: 10}];
  // x must contain exactly 7 KV pairs
  map x = 1 [(validate.rules).map = {min_pairs: 7, max_pairs: 7}];
  ```
- **no_sparse**: for map fields with message values, setting this rule to true
  disallows keys with unset values.
  ```protobuf
  // all values in x must be set
  map x = 1 [(validate.rules).map.no_sparse = true];
  ```
- **keys**: this rule specifies constraints that are applied to the keys in the
  field.
  ```protobuf
  // x's keys must all be negative
   x = [(validate.rules).map.keys.sint32.lt = 0];
  ```
- **values**: this rule specifies constraints that are be applied to each value
  in the field. Repeated message fields also have their validation rules applied
  unless `skip` is specified on this constraint.
  ```protobuf
  // x must contain strings of at least 3 characters
  map x = 1 [(validate.rules).map.values.string.min_len = 3];
  // x must contain Persons but doesn't validate them
  map x = 1 [(validate.rules).map.values.message.skip = true];
  ```
- **ignore_empty**: this rule specifies that if field is empty or set to the
  default value, to ignore any validation rules. These are typically useful
  where being able to unset a field in an update request, or to skip validation
  for optional fields where switching to WKTs is not feasible.
  ```protobuf
  map x = 1 [(validate.rules).map = {ignore_empty: true, values: {string: {min_len: 3}}}];
  ```
### Well-Known Types (WKTs)
A set of [WKTs][wkts] are packaged with protoc and common message patterns
useful in many domains.
#### Scalar Value Wrappers
In the `proto3` syntax, there is no way of distinguishing between unset and the
zero value of a scalar field. The value WKTs permit this differentiation by
wrapping them in a message. PGV permits using the same scalar rules that the
wrapper encapsulates.
```protobuf
// if it is set, x must be greater than 3
    google.protobuf.Int32Value x = 1 [(validate.rules).int32.gt = 3];
```
Message Rules can also be used with scalar Well-Known Types (WKTs):
```protobuf
// 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];}
```
#### Anys
- **required**: this rule specifies that the field must be set
  ```protobuf
  // x cannot be unset
  google.protobuf.Any x = 1 [(validate.rules).any.required = true];
  ```
- **in/not_in**: these two rules permit specifying allow/denylists for
  the `type_url` value in this field. Consider using a `oneof` union instead
  of `in` if possible.
  ```protobuf
  // 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"
    ]}];
  ```
#### Durations
- **required**: this rule specifies that the field must be set
  ```protobuf
  // x cannot be unset
  google.protobuf.Duration x = 1 [(validate.rules).duration.required = true];
  ```
- **const**: the field must be _exactly_ the specified value.
  ```protobuf
  // x must equal 1.5s exactly
  google.protobuf.Duration x = 1 [(validate.rules).duration.const = {
      seconds: 1,
      nanos:   500000000
    }];
  ```
- **lt/lte/gt/gte**: these inequalities (`<`, `<=`, `>`, `>=`, respectively)
  allow for deriving ranges in which the field must reside.
  ```protobuf
  // 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}
    }];
  ```
  Inverting the values of `lt(e)` and `gt(e)` is valid and creates an exclusive
  range.
  ```protobuf
  // x must be outside the range [0s, 1s)
  google.protobuf.Duration x = 1 [(validate.rules).duration = {
      lt:  {},
      gte: {seconds: 1}
    }];
  ```
- **in/not_in**: these two rules permit specifying allow/denylists for the
  values of a field.
  ```protobuf
  // 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}
    ]}];
  ```
#### Timestamps
- **required**: this rule specifies that the field must be set
  ```protobuf
  // x cannot be unset
  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.required = true];
  ```
- **const**: the field must be _exactly_ the specified value.
  ```protobuf
  // 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**: these inequalities (`<`, `<=`, `>`, `>=`, respectively)
  allow for deriving ranges in which the field must reside.
  ```protobuf
  // 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}
    }];
  ```
  Inverting the values of `lt(e)` and `gt(e)` is valid and creates an exclusive
  range.
  ```protobuf
  // 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**: these inequalities allow for ranges relative to the current
  time. These rules cannot be used with the absolute rules above.
  ```protobuf
  // x must be less than the current timestamp
  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.lt_now = true];
  ```
- **within**: this rule specifies that the field's value should be within a
  duration of the current time. This rule can be used in conjunction
  with `lt_now` and `gt_now` to control those ranges.
  ```protobuf
  // 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-Global
- **disabled**: All validation rules for the fields on a message can be
  nullified, including any message fields that support validation themselves.
  ```protobuf
  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;
  }
  ```
- **ignored**: Don't generate a validate method or any related validation code
  for this message.
  ```protobuf
  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
- **required**: require that one of the fields in a `oneof` must be set. By
  default, none or one of the unioned fields can be set. Enabling this rules
  disallows having all of them unset.
  ```protobuf
  oneof id {
    // either x, y, or z must be set.
    option (validate.required) = true;
    string x = 1;
    int32  y = 2;
    Person z = 3;
  }
  ```
## Development
PGV is written in Go on top of the [protoc-gen-star][pg*] framework and compiles
to a standalone binary.
### Dependencies
All PGV dependencies are currently checked into the project. To test
PGV, `protoc` must be installed, either from [source][protoc-source], the
provided [releases][protoc-releases], or a package manager. The official protoc
plugin for the target language(s) should be installed as well.
### Make Targets
- **`make build`**: generates the constraints proto and compiles PGV
  into `$GOPATH/bin`
- **`make lint`**: runs static-analysis rules against the PGV codebase,
  including `golint`, `go vet`, and `gofmt -s`
- **`make testcases`**: generates the proto files
  in [`/tests/harness/cases`](/tests/harness/cases). These are used by the test
  harness to verify the validation rules generated for each language.
- **`make harness`**: executes the test-cases against each language's test
  harness.
### Run all tests under Bazel
Ensure that your `PATH` is setup to include `protoc-gen-go` and `protoc`, then:
```
bazel test //tests/...
```
### Docker
PGV comes with a [Dockerfile](/Dockerfile) for consistent development tooling
and CI. The main entrypoint is `make` with `build` as the default target.
```sh
# build the image
docker build -t bufbuild/protoc-gen-validate .
# executes the default make target: build
docker run --rm \
  bufbuild/protoc-gen-validate
# executes the 'ci' make target
docker run --rm \
  bufbuild/protoc-gen-validate ci
# executes the 'build' & 'testcases' make targets
docker run --rm \
  bufbuild/protoc-gen-validate build testcases
  
# override the entrypoint and interact with the container directly
# this can be useful when wanting to run bazel commands without 
# bazel installed locally. 
docker run --rm \
 -it --entrypoint=/bin/bash \
 bufbuild/protoc-gen-validate
```
[protoc-source]:   https://github.com/google/protobuf
[protoc-releases]: https://github.com/google/protobuf/releases
[pg*]:             https://github.com/bufbuild/protoc-gen-star
[re2]:             https://github.com/google/re2/wiki/Syntax
[wkts]:            https://developers.google.com/protocol-buffers/docs/reference/google.protobuf