Protoc plugin to generate polyglot message validators for protocol buffers
—
The validation rules schema defines comprehensive validation constraints for all protocol buffer field types through protocol buffer extensions. These rules are applied as field options in proto files and processed by the plugin to generate validation code.
extend google.protobuf.MessageOptions {
optional bool disabled = 1071;
optional bool ignored = 1072;
}disabled: Nullifies all validation rules for the message and its fields ignored: Skips generation of validation methods entirely for the message
Usage:
message Example {
option (validate.disabled) = true;
// validation rules are ignored
}extend google.protobuf.OneofOptions {
optional bool required = 1071;
}required: Ensures exactly one field in the oneof is set
Usage:
oneof choice {
option (validate.required) = true;
string option_a = 1;
int32 option_b = 2;
}extend google.protobuf.FieldOptions {
optional FieldRules rules = 1071;
}rules: Main validation rules container for field-level constraints
message FieldRules {
optional MessageRules message = 17;
oneof type {
FloatRules float = 1;
DoubleRules double = 2;
Int32Rules int32 = 3;
Int64Rules int64 = 4;
UInt32Rules uint32 = 5;
UInt64Rules uint64 = 6;
SInt32Rules sint32 = 7;
SInt64Rules sint64 = 8;
Fixed32Rules fixed32 = 9;
Fixed64Rules fixed64 = 10;
SFixed32Rules sfixed32 = 11;
SFixed64Rules sfixed64 = 12;
BoolRules bool = 13;
StringRules string = 14;
BytesRules bytes = 15;
EnumRules enum = 16;
RepeatedRules repeated = 18;
MapRules map = 19;
AnyRules any = 20;
DurationRules duration = 21;
TimestampRules timestamp = 22;
}
}Main container for all validation rules. Contains message-level rules and a oneof for type-specific rules.
All numeric types share the same rule structure for consistency:
message FloatRules {
optional float const = 1;
optional float lt = 2;
optional float lte = 3;
optional float gt = 4;
optional float gte = 5;
repeated float in = 6;
repeated float not_in = 7;
optional bool ignore_empty = 8;
}const: Field must equal exact value lt: Field must be less than value (exclusive) lte: Field must be less than or equal to value (inclusive) gt: Field must be greater than value (exclusive) gte: Field must be greater than or equal to value (inclusive) in: Field must be one of the specified values not_in: Field cannot be any of the specified values ignore_empty: Skip validation if field is empty/default
Usage examples:
float price = 1 [(validate.rules).float = {gt: 0, lte: 1000}];
int32 count = 2 [(validate.rules).int32 = {in: [1, 5, 10, 25]}];
uint64 id = 3 [(validate.rules).uint64 = {ignore_empty: true, gt: 999}];message StringRules {
optional string const = 1;
optional uint64 len = 19;
optional uint64 min_len = 2;
optional uint64 max_len = 3;
optional uint64 min_bytes = 4;
optional uint64 max_bytes = 5;
optional string pattern = 6;
optional string prefix = 7;
optional string suffix = 8;
optional string contains = 9;
optional string not_contains = 23;
repeated string in = 10;
repeated string not_in = 11;
optional bool email = 12;
optional bool hostname = 13;
optional bool ip = 14;
optional bool ipv4 = 15;
optional bool ipv6 = 16;
optional bool uri = 17;
optional bool uri_ref = 18;
optional bool address = 21;
optional bool uuid = 22;
optional KnownRegex well_known_regex = 24;
optional bool strict = 25;
optional bool ignore_empty = 26;
}const: Exact string match len: Exact character length (Unicode code points) min_len/max_len: Minimum/maximum character length min_bytes/max_bytes: Minimum/maximum byte length pattern: RE2-compliant regular expression match prefix/suffix: Required prefix/suffix contains/not_contains: Required/forbidden substring in/not_in: Allowed/disallowed string values email: RFC 5322 email format validation hostname: RFC 1034 hostname format validation ip: IP address format (v4 or v6) ipv4/ipv6: Specific IP version format uri: RFC 3986 absolute URI format uri_ref: URI reference format (absolute or relative) address: Valid address (IP or hostname) uuid: RFC 4122 UUID format well_known_regex: Predefined regex patterns strict: Strict format validation mode ignore_empty: Skip validation if empty
Usage examples:
string email = 1 [(validate.rules).string.email = true];
string name = 2 [(validate.rules).string = {min_len: 1, max_len: 100}];
string token = 3 [(validate.rules).string.uuid = true];message BytesRules {
optional bytes const = 1;
optional uint64 len = 13;
optional uint64 min_len = 2;
optional uint64 max_len = 3;
optional string pattern = 4;
optional bytes prefix = 5;
optional bytes suffix = 6;
optional bytes contains = 7;
repeated bytes in = 8;
repeated bytes not_in = 9;
optional bool ip = 10;
optional bool ipv4 = 11;
optional bool ipv6 = 12;
optional bool ignore_empty = 14;
}Similar to StringRules but for byte sequences: const: Exact byte sequence match len: Exact byte length min_len/max_len: Minimum/maximum byte length pattern: RE2 regex pattern for byte content prefix/suffix/contains: Required byte subsequences in/not_in: Allowed/disallowed byte values ip/ipv4/ipv6: IP address in byte format ignore_empty: Skip validation if empty
message BoolRules {
optional bool const = 1;
}const: Exact boolean value required
message EnumRules {
optional int32 const = 1;
optional bool defined_only = 2;
repeated int32 in = 3;
repeated int32 not_in = 4;
}const: Exact enum value (numeric) defined_only: Must be a defined enum value in/not_in: Allowed/disallowed enum values
message MessageRules {
optional bool skip = 1;
optional bool required = 2;
}skip: Skip validation of message fields required: Message field must be set (not null)
message RepeatedRules {
optional uint64 min_items = 1;
optional uint64 max_items = 2;
optional bool unique = 3;
optional FieldRules items = 4;
optional bool ignore_empty = 5;
}min_items/max_items: Minimum/maximum number of items unique: All items must be unique (not supported for messages) items: Validation rules applied to each item ignore_empty: Skip validation if empty
message MapRules {
optional uint64 min_pairs = 1;
optional uint64 max_pairs = 2;
optional bool no_sparse = 3;
optional FieldRules keys = 4;
optional FieldRules values = 5;
optional bool ignore_empty = 6;
}min_pairs/max_pairs: Minimum/maximum key-value pairs no_sparse: Disallow unset message values keys: Validation rules for map keys values: Validation rules for map values ignore_empty: Skip validation if empty
message AnyRules {
optional bool required = 1;
repeated string in = 2;
repeated string not_in = 3;
}required: Any field must be set in/not_in: Allowed/disallowed type URLs
message DurationRules {
optional bool required = 1;
optional google.protobuf.Duration const = 2;
optional google.protobuf.Duration lt = 3;
optional google.protobuf.Duration lte = 4;
optional google.protobuf.Duration gt = 5;
optional google.protobuf.Duration gte = 6;
repeated google.protobuf.Duration in = 7;
repeated google.protobuf.Duration not_in = 8;
}required: Duration field must be set const: Exact duration value lt/lte/gt/gte: Duration comparison constraints in/not_in: Allowed/disallowed duration values
message TimestampRules {
optional bool required = 1;
optional google.protobuf.Timestamp const = 2;
optional google.protobuf.Timestamp lt = 3;
optional google.protobuf.Timestamp lte = 4;
optional google.protobuf.Timestamp gt = 5;
optional google.protobuf.Timestamp gte = 6;
optional bool lt_now = 7;
optional bool gt_now = 8;
optional google.protobuf.Duration within = 9;
repeated google.protobuf.Timestamp in = 10;
repeated google.protobuf.Timestamp not_in = 11;
}required: Timestamp field must be set const: Exact timestamp value lt/lte/gt/gte: Timestamp comparison constraints lt_now/gt_now: Comparison relative to current time within: Must be within duration of current time in/not_in: Allowed/disallowed timestamp values
enum KnownRegex {
UNKNOWN = 0;
HTTP_HEADER_NAME = 1;
HTTP_HEADER_VALUE = 2;
}Predefined regex patterns for common validation needs:
HTTP_HEADER_NAME: RFC 7230 HTTP header name format (^:?[0-9a-zA-Z!#$%&'*+-.^_|~\x60]+$)
HTTP_HEADER_VALUE: RFC 7230 HTTP header value format (^[^\u0000-\u0008\u000A-\u001F\u007F]*$)
HEADER_STRING: Non-strict header validation (^[^\u0000\u000A\u000D]*$)
Install with Tessl CLI
npx tessl i tessl/go-protoc-gen-validate