Skip to content

Emit protovalidate constraints for core TypeSpec decorators #11227

Description

Following up on #4090 and #7838 (cc Denis (@rhodee) & Will Temple (@witemple-msft)) I put together a working implementation and wanted to check whether it covers what you're after before opening a PR.

The idea: the protobuf emitter currently drops the constraint information people already put on their models. If you write @minLength, @maxValue, @pattern, @format, etc., none of it makes it into the generated .proto. Those decorators are core TypeSpec and the OpenAPI emitter already honours them, so rather than invent anything protobuf-specific, the emitter can translate them into the ecosystem-standard buf.validate field options.

It's behind an opt-in emitter option (emit-protovalidate). When it's on, any file that emits at least one constraint also gets import "buf/validate/validate.proto";.

e.g.:

model User {
  @field(1) @minLength(3) @maxLength(32) @pattern("^[a-z0-9_]+$") username: string;
  @field(2) @format("email") email: string;
  @field(3) @minValue(0) @maxValue(150) age: int32;
  @field(4) @minItems(1) @maxItems(10) roles: string[];
}

produces:

import "buf/validate/validate.proto";

message User {
  string username = 1 [(buf.validate.field).string.min_len = 3, (buf.validate.field).string.max_len = 32, (buf.validate.field).string.pattern = "^[a-z0-9_]+$"];
  string email = 2 [(buf.validate.field).string.email = true];
  int32 age = 3 [(buf.validate.field).int32.gte = 0, (buf.validate.field).int32.lte = 150];
  repeated string roles = 4 [(buf.validate.field).repeated.min_items = 1, (buf.validate.field).repeated.max_items = 10];
}

Currently mapped:

  • @minValue -> <type>.gte, @maxValue -> <type>.lte, @minValueExclusive -> <type>.gt, @maxValueExclusive -> <type>.lt (where <type> is the field's numeric proto type, e.g. int32, sint64, double)
  • @minLength -> string.min_len, @maxLength -> string.max_len
  • @pattern -> string.pattern
  • @minItems -> repeated.min_items, @maxItems -> repeated.max_items
  • @format -> the matching string rule for the values with a direct buf.validate analogue: email, uuid, hostname, ip, ipv4, ipv6, uri

I didn't add anything that isn't already expressable by TypeSpec decorators, even if it had a protovalidate representation (CEL cross-field expressions, required/ignore semantics, well-known-type rules). Those would need new protobuf-specific decorators, which felt like a separate conversation (and closer to #4090).

Denis (@rhodee) -- does this cover your use case, or were you relying on any of the out-of-scope pieces above? And for the maintainers: if the general direction is acceptable, I'm happy to open the PR.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions