Protobuf3: String validation with regex
Protobuf does not support message validation out of the box, but it is possible to add it using plugin (that's the only way, however, it is not simple).
You can try to find existing plugin, or create your own (if there is no existing plugin for your language).
If you decide to write your own plugin, then first step is to define a custom option for fields:
package yourcompany;
import "google/protobuf/descriptor.proto";
extend google.protobuf.FieldOptions {
optional string validator = 51234;
}
This option allows you to specify regular expression for a concrete field. Then you apply your new custom option:
message Update {
string sensor_id = 1 [(yourcompany.validator) = "SENSOR-???????"];
// ...
}
Second, and more challenging step is to write your own plugin in order to add validation logic to generated code:
Additionally, plugins are able to insert code into the files generated by other code generators. See the comments about "insertion points" in plugin.proto for more on this. This could be used, for example, to write a plugin which generates RPC service code that is tailored for a particular RPC system. See the documentation for the generated code in each language to find out what insertion points they provide.
Your plugin must check value of your custom option and generate additional validation code for fields.
Please check this project protoc-gen-validate https://github.com/envoyproxy/protoc-gen-validate
I wrote an example for Golang here https://github.com/alexcpn/golang_grpc_test
With this you can give semantic validation as a annotation in proto and get it autogenerated as part of protobuff generation
message SearchRequest {
string query = 1 [(validate.rules).string = {
pattern: "([A-Za-z]+) ([A-Za-z]+)*$",
max_bytes: 50,
}];
string email_id= 2 [(validate.rules).string.email = true];
int32 page_number = 3; // Which page number do we want?
int32 result_per_page = 4; // Number of results to return per page.
}
Server validation using generated stub
func (s *Server)Search(ctx context.Context, in *pb.SearchRequest) (*pb.SearchResponse, error){
log.Printf("Received Emailid: %v", in.EmailId)
log.Printf("Received Query: %v", in.Query)
// Note this is the only place we use validate
err := in.Validate()
if err != nil {
log.Warn("SearchRequest validation failed: %v", err)