CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/go-protoc-gen-validate

Protoc plugin to generate polyglot message validators for protocol buffers

Pending
Overview
Eval results
Files

runtime-libraries.mddocs/

Runtime Libraries

Runtime libraries provide language-specific utilities, validation support, and integration helpers for protoc-gen-validate generated code. Each target language has different runtime requirements and capabilities.

Go Runtime

Go generated code has zero runtime dependencies and integrates directly with existing protobuf Go libraries.

Generated Code Integration

Generated validation methods are added directly to protobuf message types:

// No additional runtime library required
// Methods are generated directly on message types
func (m *Message) Validate() error
func (m *Message) ValidateAll() error

Error Handling

Uses standard Go error interface with contextual error messages:

// Example error patterns generated in validation code
return fmt.Errorf("invalid %s.%s: %s", messageType, fieldName, constraint)

Integration Utilities

While no runtime library is required, common integration patterns include:

// HTTP middleware example (user-implemented)
func ValidateRequest(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    var req proto.Message
    // ... decode request
    if err := req.(interface{ Validate() error }).Validate(); err != nil {
      http.Error(w, err.Error(), http.StatusBadRequest)
      return
    }
    next.ServeHTTP(w, r)
  })
}

Java Runtime

Java runtime provides validator discovery, caching, and gRPC integration through the pgv-java-stub library.

Core Runtime Classes

class ReflectiveValidatorIndex implements ValidatorIndex {
  public Validator validatorFor(Class<?> clazz);
}

Reflection-based validator discovery and caching.

Methods:

  • validatorFor(Class<?> clazz): Returns cached validator for message class

Usage:

ValidatorIndex index = new ReflectiveValidatorIndex();
Validator<UserProto> validator = index.validatorFor(UserProto.class);
validator.assertValid(user);

Validator Interface

interface Validator<T> {
  void assertValid(T message) throws ValidationException;
}

Base interface implemented by all generated validators.

Exception Types

class ValidationException extends Exception {
  public ValidationException(String message);
  public String getFieldPath();
  public Object getInvalidValue();
}

Exception thrown by validators on validation failure.

gRPC Integration

class ValidatingClientInterceptor implements ClientInterceptor {
  public ValidatingClientInterceptor(ValidatorIndex index);
}

Client-side gRPC interceptor for automatic request/response validation.

class ValidatingServerInterceptor implements ServerInterceptor {
  public ValidatingServerInterceptor(ValidatorIndex index);
}

Server-side gRPC interceptor for automatic request/response validation.

Usage:

// Client setup
ValidatorIndex index = new ReflectiveValidatorIndex();
ManagedChannel channel = NettyChannelBuilder.forAddress("localhost", 8080)
  .usePlaintext()
  .build();
UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc.newBlockingStub(channel)
  .withInterceptors(new ValidatingClientInterceptor(index));

// Server setup
Server server = ServerBuilder.forPort(8080)
  .addService(ServerInterceptors.intercept(
    new UserServiceImpl(), 
    new ValidatingServerInterceptor(index)
  ))
  .build();

Maven Integration

<dependency>
  <groupId>build.buf.protoc-gen-validate</groupId>
  <artifactId>pgv-java-stub</artifactId>
  <version>${pgv.version}</version>
</dependency>

Python Runtime

Python provides a full runtime library for JIT validation function generation and caching.

Core Runtime Module

# protoc_gen_validate.validator module

Main module containing validation functionality.

Validation Functions

def validate(proto_message: Message)

Main validation function that dynamically generates and executes validation code.

Parameters:

  • msg: Protobuf message instance to validate

Raises: ValidationFailed when validation fails

Implementation:

  • Generates validation function code dynamically based on message descriptor
  • Uses exec() to compile and execute validation logic
  • Caches compiled functions using LRU cache for performance
def validate_all(proto_message: Message)

Validates message and returns all validation errors instead of raising exception on first error.

Parameters:

  • proto_message: Message: Protocol buffer message to validate

Raises: ValidationFailed with all validation error messages

def print_validate(msg) -> None

Debug utility that prints generated validation code.

Parameters:

  • msg: Protobuf message instance

Behavior:

  • Generates the same validation code as validate()
  • Prints Python code to stdout for debugging
  • Useful for understanding validation logic

Exception Types

class ValidatingMessage(object):
  """Wrap a proto message to cache validate functions"""
  def __init__(self, proto_message: Message)
  def __hash__(self) -> int
  def __eq__(self, other) -> bool

class ValidationFailed(Exception):
  """Raised when message validation fails"""
  pass

Exception raised when validation fails.

Usage:

from protoc_gen_validate.validator import validate, ValidationFailed

try:
    validate(message)
except ValidationFailed as e:
    logger.error(f"Validation failed: {e}")

Performance Features

# Internal caching mechanism (implementation detail)
@lru_cache(maxsize=128)
def _get_validator_func(descriptor_name):
    # Returns cached validation function
    pass

Performance optimizations:

  • LRU Cache: Validation functions cached by message descriptor
  • JIT Compilation: Functions compiled on first use
  • Code Reuse: Shared validation logic across similar message types

Installation

pip install protoc-gen-validate

C++ Runtime

C++ generated code has minimal runtime dependencies and uses standard library types.

Generated Function Pattern

namespace validate {
  bool Validate(const Message& msg, std::string* error = nullptr);
}

Generated validation functions follow consistent pattern:

  • Return bool for validation result
  • Optional std::string* parameter for error details
  • Const reference parameter for message

Dependencies

C++ runtime requires only standard library and protobuf headers:

#include <string>
#include <google/protobuf/message.h>
// Generated validation headers

Error Handling

// Error handling pattern
std::string error;
if (!validate::Validate(message, &error)) {
  // Handle validation failure
  std::cerr << "Validation failed: " << error << std::endl;
}

Integration Examples

// Service layer integration
class UserService {
 public:
  Status CreateUser(const CreateUserRequest& request) {
    std::string validation_error;
    if (!validate::Validate(request, &validation_error)) {
      return Status(StatusCode::kInvalidArgument, validation_error);
    }
    // Process valid request
    return Status::OK;
  }
};

Cross-Language Runtime Comparison

Feature Matrix

FeatureGoJavaC++Python
Runtime DependenciesNonepgv-java-stubStandard libraryprotoc-gen-validate
Error Typeserror interfaceValidationExceptionstd::stringValidationFailed
PerformanceZero allocationReflection cacheStatic validationJIT with cache
gRPC IntegrationManualBuilt-in interceptorsManualManual
Framework IntegrationManualSpring/JAX-RS readyManualDjango/Flask ready

Consistency Guarantees

All runtimes maintain:

  • Identical validation logic for the same proto rules
  • Consistent error detection across languages
  • Similar performance characteristics relative to language capabilities
  • Compatible error messaging for debugging

Installation Methods

Go:

# No runtime installation needed
# Generated code has zero dependencies

Java:

<!-- Maven -->
<dependency>
  <groupId>build.buf.protoc-gen-validate</groupId>
  <artifactId>pgv-java-stub</artifactId>
  <version>${pgv.version}</version>
</dependency>

C++:

# No runtime installation needed  
# Generated code uses standard library

Python:

pip install protoc-gen-validate

Performance Considerations

Go Performance

  • Zero heap allocations for valid messages
  • Compile-time optimized validation logic
  • Direct method calls, no reflection

Java Performance

  • Reflection-based but with caching
  • Validator instances cached by class
  • gRPC interceptor overhead minimal

C++ Performance

  • Compile-time optimized validation
  • Stack-based error handling
  • Minimal function call overhead

Python Performance

  • JIT compilation overhead on first use
  • LRU cache eliminates repeated compilation
  • Dynamic execution with exec() overhead

Testing and Development

Runtime Testing Support

All runtimes support:

  • Unit testing of validation logic
  • Mock validation for testing
  • Performance benchmarking
  • Integration testing utilities

Development Tools

Language-specific development aids:

  • Go: Built-in testing framework integration
  • Java: JUnit integration examples
  • C++: GoogleTest integration patterns
  • Python: pytest integration and debug utilities

Install with Tessl CLI

npx tessl i tessl/go-protoc-gen-validate

docs

code-generation.md

core-plugin.md

generated-code.md

index.md

runtime-libraries.md

validation-rules.md

tile.json