Skip to content

Validation

Validation starts with Protobuf's generated type contracts and extends into explicit schema-level rules with protovalidate.

Generated Protobuf code enforces the schema's structural types: strings are strings, integers are numbers, repeated fields are collections, and nested messages have the expected shape.

This is useful validation, but it is intentionally limited. A schema type can tell you that a field is a string; it cannot tell you that the string is a valid email address, that an age is in range, or that two fields satisfy a business rule.

The next layer is to describe those expectations in the schema itself, using annotations that tools can read consistently across services and languages.

message SignupRequest {
  string email = 1;
  uint32 age = 2;
  repeated string roles = 3;
}

Once the structural shape is stable, the next question is where to put the rules that make the data meaningful: email format, ranges, required fields, cross-field checks, and domain-specific constraints.

Keeping those rules close to the schema makes them available to generated code, gateways, tests, CLIs, and runtime validation tools without each service reinventing the same checks.

The Source of Truth

Protobuf allows you to build additional structure on top of basic field types. By using extensions, you can augment your schema with rich metadata. This is how protovalidate works: it embeds validation rules directly into your schema using CEL. Try modifying the JSON data below or clicking the example buttons to see the validation rules in action.

Test Data (JSON)

JSON input
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Hiro Protagonist",
  "email": "hiro@metaverse.com",
  "age": 30,
  "role": 2,
  "birthDate": {
    "year": 1996,
    "month": 1,
    "day": 1
  }
}

Rules Enforcement

Validation status

Waiting for
valid input

Validation Strategy

By putting validation in the schema, you ensure that every part of your system enforcing the contract applies the exact same rules. This eliminates "validation drift" across your entire stack, not only between microservices. For instance, you can use the same rules to validate a form on your web frontend (using TypeScript) before the request ever hits your backend (running Go, Java, etc.).