Skip to content

emicklei/protocheck

Repository files navigation

protocheck

Go GoDoc codecov

Lightweight solution to ProtocolBuffers message validation. protocheck-proto-gen is a protoc plugin that generates code.

features

  • expressions with Google/CEL
  • both message and field checks
  • nested messages
  • repeated, oneof and map fields
  • syntax validation of CEL expressions at generation time
  • supports proto3 and edition 2023 (default_api_level=API_OPAQUE)
  • supported languages:
    • Go
    • Java

install

  go install github.com/emicklei/protocheck/cmd/protoc-gen-protocheck@latest

example

package hr;

import "check.proto";

message Person {
  
  // message cross-field checks
  option (check.message) = { 
    cel:"size(this.name + this.surname) > 0"  // cel is required
    fail:"name and surname cannot be empty"  // fail is optional
    id:"person_invariant" }; // id is optional
  
  // with per field state checks
  string name = 1 [(check.field) = { 
      cel:"size(this.name) > 1"                  
      fail:"name must be longer than 1" }];

  optional string middle_name = 2 [(check.field) = { 
      cel:"size(this.middle_name) > 0"           
      fail:"middle name (if set) cannot be empty" }];

  string surname = 3 [(check.field) = { 
      cel:"size(this.surname) > 1"               
      fail:"surname must be longer than 1" }];

  google.protobuf.Timestamp birth_date  = 4 [(check.field) = { 
      cel:"this.birth_date.getFullYear() > 2000" 
      id:"check_birth_date" }];

getFullYear is one of the supported CEL macros.

See CEL language definition for creating CEL expressions.

generate Go

	protoc -I=../protos \
		--go_out=. \
		--go_opt=paths=source_relative \
		--protocheck_out=. \
		--protocheck_opt=paths=source_relative,lang=go \
	person.proto

You can add the option v=true to produce verbose logging of the protocheck tool.

usage Go

p := &Person{
    Name:      "",
    BirthDate: &timestamppb.Timestamp{Seconds:1}
}
if err := p.Validate(); err != nil {
  for _ , each := range err {
    log.Println(each)
  }
}

generate Java

	protoc -I=../protos \
		--java_out=src/main/java \
		--protocheck_out=src/main/java \
		--protocheck_opt=paths=source_relative,lang=java \
		person.proto

usage Java

  Person p = Person.newBuilder()
          .setName("")
          .build();
  for (CheckError e : OuterClassName.validate(p)) {
      System.err.println(e);
  }

considerations

The protocheck package is inspired by bufbuild/protovalidate which also uses the powerful CEL expression language. However, it differs by:

  • this always refers to the message
  • minimal dependencies (cel and protobuf)
  • syntax is more compact

About

lightweight minimal ProtocolBuffer message validation package and code generation

Topics

Resources

License

Stars

Watchers

Forks