protovalidate-cc
is the C++ language implementation
of protovalidate
designed
to validate Protobuf messages at runtime based on user-defined validation constraints.
Powered by Google's Common Expression Language (CEL), it provides a
flexible and efficient foundation for defining and evaluating custom validation
rules.
The primary goal of protovalidate
is to help developers ensure data
consistency and integrity across the network without requiring generated code.
Head over to the core protovalidate
repository for:
- The API definition: used to describe validation constraints
- Documentation: how to apply
protovalidate
effectively - Migration tooling: incrementally migrate from
protoc-gen-validate
- Conformance testing utilities: for acceptance testing of
protovalidate
implementations
Other protovalidate
runtime implementations include
- Go:
protovalidate-go
- Java:
protovalidate-java
- Python:
protovalidate-python
And others coming soon:
- TypeScript:
protovalidate-ts
To install protovalidate-cc
, clone the repository and build the project:
git clone https://github.com/bufbuild/protovalidate-cc.git
cd protovalidate-cc
make build
Remember to always check for the latest version of protovalidate-cc
on the
project's GitHub releases page
to ensure you're using the most up-to-date version.
To use protovalidate-cc
as an external Bazel repository, add the following to the WORKSPACE
file:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_github_bufbuild_protovalidate_cc",
sha256 = ...,
strip_prefix = "protovalidate-cc-{verion}",
urls = [
"https://github.com/bufbuild/protovalidate-cc/archive/v{verion}.tar.gz",
],
)
load("@com_github_bufbuild_protovalidate_cc//bazel:deps.bzl", "protovalidate_cc_dependencies")
protovalidate_cc_dependencies()
Then add a dependency to a cc_library
or cc_binary
target:
cc_library(
...
deps = [
"@com_github_bufbuild_protovalidate_cc//buf/validate:validator",
...
]
)
Validation constraints are defined directly within .proto
files.
Documentation for adding constraints can be found in the protovalidate
project
README and its comprehensive docs.
syntax = "proto3";
package my.package;
import "google/protobuf/timestamp.proto";
import "buf/validate/validate.proto";
message Transaction {
uint64 id = 1 [(buf.validate.field).uint64.gt = 999];
google.protobuf.Timestamp purchase_date = 2;
google.protobuf.Timestamp delivery_date = 3;
string price = 4 [(buf.validate.field).cel = {
id: "transaction.price",
message: "price must be positive and include a valid currency symbol ($ or £)",
expression: "(this.startsWith('$') || this.startsWith('£')) && double(this.substring(1)) > 0"
}];
option (buf.validate.message).cel = {
id: "transaction.delivery_date",
message: "delivery date must be after purchase date",
expression: "this.delivery_date > this.purchase_date"
};
}
In your C++ code, include the header file and use the Validate
function to validate your messages.
#include <iostream>
#include "buf/validate/validator.h"
#include "google/protobuf/arena.h"
#include "path/to/generated/protos/transaction.pb.h"
int main() {
my::package::Transaction transaction;
transaction.set_id(1234);
transaction.set_price("$5.67");
google::protobuf::Timestamp* purchase_date = transaction.mutable_purchase_date();
google::protobuf::Timestamp* delivery_date = transaction.mutable_delivery_date();
// set time for purchase_date and delivery_date
std::unique_ptr<buf::validate::ValidatorFactory> factory =
buf::validate::ValidatorFactory::New().value();
google::protobuf::Arena arena;
buf::validate::Validator validator = factory->NewValidator(&arena);
buf::validate::Violations results = validator.Validate(transaction).value();
if (results.violations_size() > 0) {
std::cout << "validation failed" << std::endl;
} else {
std::cout << "validation succeeded" << std::endl;
}
return 0;
}
protovalidate
core repository- Buf
- CEL Spec
Offered under the Apache 2 license.