Convert Figma logo to code with AI

mwitkow logogo-proto-validators

Generate message validators from .proto annotations.

1,084
164
1,084
46

Top Related Projects

Go support for Google's protocol buffers

Go support for Google's protocol buffers

Protocol Buffer Validation - Being replaced by github.com/bufbuild/protovalidate

Quick Overview

The mwitkow/go-proto-validators project is a Go library that provides a set of validation rules for Protocol Buffers (protobuf) messages. It allows developers to define validation constraints directly in the protobuf schema, which can then be automatically enforced at runtime.

Pros

  • Declarative Validation: The library allows developers to define validation rules directly in the protobuf schema, making it easier to manage and maintain validation logic.
  • Automatic Validation: The generated code from the protobuf compiler automatically includes the validation logic, reducing the amount of boilerplate code that developers need to write.
  • Extensibility: The library provides a set of built-in validation rules, but also allows developers to define custom validation rules as needed.
  • Integration with Existing Tooling: The library integrates well with the existing protobuf toolchain, making it easy to incorporate into existing projects.

Cons

  • Dependency on Protobuf: The library is tightly coupled with the protobuf ecosystem, which may not be suitable for projects that do not use protobuf.
  • Limited Validation Types: While the library provides a set of built-in validation rules, it may not cover all the validation requirements that developers might have.
  • Performance Impact: Depending on the complexity of the validation rules, the library may have a performance impact on the application.
  • Lack of Comprehensive Documentation: The project's documentation could be more comprehensive, making it harder for new users to get started.

Code Examples

Here are a few examples of how to use the mwitkow/go-proto-validators library:

  1. Defining Validation Rules in the Protobuf Schema:
message Person {
  string name = 1 [(validator.field) = {string_not_empty: true}];
  int32 age = 2 [(validator.field) = {int_gt: 0, int_lt: 150}];
  repeated string emails = 3 [(validator.field) = {repeated_min_items: 1, repeated_max_items: 5}];
}
  1. Validating a Protobuf Message:
import (
    "github.com/mwitkow/go-proto-validators"
)

func ValidatePerson(p *Person) error {
    if _, err := validators.ValidateStruct(p); err != nil {
        return err
    }
    return nil
}
  1. Defining a Custom Validation Rule:
import (
    "github.com/mwitkow/go-proto-validators"
)

func init() {
    validators.RegisterValidatorFunc("is_even", func(v interface{}) error {
        if i, ok := v.(int32); ok {
            if i%2 != 0 {
                return fmt.Errorf("%d is not an even number", i)
            }
        }
        return nil
    })
}

message Person {
  int32 age = 2 [(validator.field) = {is_even: true}];
}

Getting Started

To get started with the mwitkow/go-proto-validators library, follow these steps:

  1. Install the library using Go modules:
go get github.com/mwitkow/go-proto-validators
  1. Define your protobuf messages with validation rules:
syntax = "proto3";

package example;

import "github.com/mwitkow/go-proto-validators/validator.proto";

message Person {
  string name = 1 [(validator.field) = {string_not_empty: true}];
  int32 age = 2 [(validator.field) = {int_gt: 0, int_lt: 150}];
  repeated string emails = 3 [(validator.field) = {repeated_min_items: 1, repeated_max_items: 5}];
}
  1. Generate the Go code for your protobuf messages:
protoc --go_out=. --go-validator_out=. example.proto
  1. Use the generated validation functions in your Go code:
import

Competitor Comparisons

Go support for Google's protocol buffers

Pros of protobuf-go

  • Official implementation by Google, ensuring compatibility and long-term support
  • Comprehensive support for all Protocol Buffers features
  • Optimized performance for encoding and decoding

Cons of protobuf-go

  • Lacks built-in validation functionality
  • Requires additional code or libraries for custom validation rules

Code Comparison

go-proto-validators:

message User {
  string email = 1 [(validator.field) = {regex: "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$"}];
  int32 age = 2 [(validator.field) = {int_gt: 0, int_lt: 120}];
}

protobuf-go (with custom validation):

type User struct {
    Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
    Age   int32  `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
}

func (u *User) Validate() error {
    if !regexp.MustCompile(`^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$`).MatchString(u.Email) {
        return errors.New("invalid email format")
    }
    if u.Age <= 0 || u.Age >= 120 {
        return errors.New("age must be between 1 and 119")
    }
    return nil
}

go-proto-validators provides a more concise and declarative way to define validation rules directly in the protocol buffer definition. protobuf-go requires manual implementation of validation logic in Go code, which can be more verbose but offers greater flexibility for complex validation scenarios.

Go support for Google's protocol buffers

Pros of protobuf

  • Official Google implementation, ensuring compatibility and long-term support
  • Comprehensive feature set covering all aspects of Protocol Buffers
  • Extensive documentation and community support

Cons of protobuf

  • Lacks built-in validation features for generated Go code
  • More complex to use for simple validation tasks
  • Requires additional code or libraries for custom validations

Code Comparison

go-proto-validators:

message User {
  string name = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
  int32 age = 2 [(validator.field) = {int_gt: 0, int_lt: 100}];
}

protobuf:

message User {
  string name = 1;
  int32 age = 2;
}

// Additional validation code required

Key Differences

  • go-proto-validators focuses on adding validation rules directly in .proto files
  • protobuf provides a more general-purpose implementation without built-in validations
  • go-proto-validators simplifies the validation process for Go developers
  • protobuf requires manual implementation of validation logic in Go code

Use Cases

  • Choose go-proto-validators for projects requiring extensive field validations
  • Opt for protobuf in larger projects needing full Protocol Buffers functionality
  • Consider go-proto-validators for rapid development with built-in validations
  • Use protobuf when working with multiple languages or requiring official support

Protocol Buffer Validation - Being replaced by github.com/bufbuild/protovalidate

Pros of protoc-gen-validate

  • Multi-language support: Generates validators for Go, C++, Java, and Python
  • More extensive validation options, including complex rules and cross-field validations
  • Active development and maintenance with regular updates

Cons of protoc-gen-validate

  • Steeper learning curve due to more complex syntax and options
  • Potentially larger generated code size for simple validations

Code Comparison

go-proto-validators:

message Example {
  string email = 1 [(validator.field) = {regex: "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$"}];
}

protoc-gen-validate:

message Example {
  string email = 1 [(validate.rules).string = {
    email: true,
    max_len: 100
  }];
}

Both libraries provide validation for Protocol Buffer messages, but protoc-gen-validate offers more comprehensive features and multi-language support. go-proto-validators is simpler and more lightweight, focusing solely on Go. The code comparison shows that protoc-gen-validate has a more structured approach to defining validation rules, while go-proto-validators uses a more compact syntax. Choose based on your project's complexity, language requirements, and desired level of validation granularity.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Golang ProtoBuf Validator Compiler

Travis Build Apache 2.0 License

A protoc plugin that generates Validate() error functions on Go proto structs based on field options inside .proto files. The validation functions are code-generated and thus don't suffer on performance from tag-based reflection on deeply-nested messages.

Requirements

Using Protobuf validators is currently verified to work with:

It should still be possible to use it in project using earlier Go versions. However if you want to contribute to this repository you'll need at least 1.11 for Go module support.

Paint me a code picture

Let's take the following proto3 snippet:

syntax = "proto3";
package validator.examples;
import "github.com/mwitkow/go-proto-validators/validator.proto";

message InnerMessage {
  // some_integer can only be in range (0, 100).
  int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}];
  // some_float can only be in range (0;1).
  double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}];
}

message OuterMessage {
  // important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax).
  string important_string = 1 [(validator.field) = {regex: "^[a-z0-9]{5,30}$"}];
  // proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage.
  InnerMessage inner = 2 [(validator.field) = {msg_exists : true}];
}

First, the required keyword is back for proto3, under the guise of msg_exists. The painful if-nil checks are taken care of!

Second, the expected values in fields are now part of the contract .proto file. No more hunting down conditions in code!

Third, the generated code is understandable and has clear understandable error messages. Take a look:

func (this *InnerMessage) Validate() error {
	if !(this.SomeInteger > 0) {
		return fmt.Errorf("validation error: InnerMessage.SomeInteger must be greater than '0'")
	}
	if !(this.SomeInteger < 100) {
		return fmt.Errorf("validation error: InnerMessage.SomeInteger must be less than '100'")
	}
	if !(this.SomeFloat >= 0) {
		return fmt.Errorf("validation error: InnerMessage.SomeFloat must be greater than or equal to '0'")
	}
	if !(this.SomeFloat <= 1) {
		return fmt.Errorf("validation error: InnerMessage.SomeFloat must be less than or equal to '1'")
	}
	return nil
}

var _regex_OuterMessage_ImportantString = regexp.MustCompile("^[a-z0-9]{5,30}$")

func (this *OuterMessage) Validate() error {
	if !_regex_OuterMessage_ImportantString.MatchString(this.ImportantString) {
		return fmt.Errorf("validation error: OuterMessage.ImportantString must conform to regex '^[a-z0-9]{5,30}$'")
	}
	if nil == this.Inner {
		return fmt.Errorf("validation error: OuterMessage.Inner message must exist")
	}
	if this.Inner != nil {
		if err := validators.CallValidatorIfExists(this.Inner); err != nil {
			return err
		}
	}
	return nil
}

Installing and using

The protoc compiler expects to find plugins named proto-gen-XYZ on the execution $PATH. So first:

export PATH=${PATH}:${GOPATH}/bin

Then, do the usual

go get github.com/mwitkow/go-proto-validators/protoc-gen-govalidators

Your protoc builds probably look very simple like:

protoc  \
  --proto_path=. \
  --go_out=. \
  *.proto

That's fine, until you encounter .proto includes. Because go-proto-validators uses field options inside the .proto files themselves, it's .proto definition (and the Google descriptor.proto itself) need to on the protoc include path. Hence the above becomes:

protoc  \
  --proto_path=${GOPATH}/src \
  --proto_path=${GOPATH}/src/github.com/google/protobuf/src \
  --proto_path=. \
  --go_out=. \
  --govalidators_out=. \
  *.proto

Or with gogo protobufs:

protoc  \
  --proto_path=${GOPATH}/src \
  --proto_path=${GOPATH}/src/github.com/gogo/protobuf/protobuf \
  --proto_path=. \
  --gogo_out=. \
  --govalidators_out=gogoimport=true:. \
  *.proto

Basically the magical incantation (apart from includes) is the --govalidators_out. That triggers the protoc-gen-govalidators plugin to generate mymessage.validator.pb.go. That's it :)

License

go-proto-validators is released under the Apache 2.0 license. See the LICENSE file for details.