Convert Figma logo to code with AI

jhump logoprotoreflect

Reflection (Rich Descriptors) for Go Protocol Buffers

1,332
170
1,332
11

Top Related Projects

[Deprecated] Protocol Buffers for Go with Gadgets

Go support for Google's protocol buffers

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

Quick Overview

The jhump/protoreflect project is a Go library that provides a set of tools for working with Protocol Buffers (protobuf), a popular data serialization format. It offers a comprehensive set of APIs for parsing, manipulating, and generating protobuf-based code, making it a valuable resource for developers working with protobuf in Go.

Pros

  • Comprehensive Protobuf Support: The library provides a wide range of functionality for working with protobuf, including parsing, reflection, and code generation.
  • Flexibility: The library is designed to be highly flexible, allowing developers to customize and extend its behavior to fit their specific needs.
  • Performance: The library is optimized for performance, making it a suitable choice for high-performance applications.
  • Active Development: The project is actively maintained and regularly updated, ensuring that it stays up-to-date with the latest protobuf specifications and best practices.

Cons

  • Steep Learning Curve: The library's extensive functionality and flexibility can make it challenging for newcomers to get started, especially if they are not familiar with protobuf or Go.
  • Limited Documentation: While the project has a decent amount of documentation, some areas may be lacking in detailed explanations and examples.
  • Dependency on Protobuf: The library is tightly coupled with the protobuf ecosystem, which means that developers who are not using protobuf may not find it useful.
  • Potential Performance Overhead: Depending on the specific use case, the library's flexibility and comprehensive feature set may introduce some performance overhead compared to more lightweight protobuf libraries.

Code Examples

Here are a few code examples demonstrating the usage of the jhump/protoreflect library:

  1. Parsing a Protobuf Message:
import (
    "fmt"
    "github.com/jhump/protoreflect/desc"
    "github.com/jhump/protoreflect/dynamic"
)

// Parse a protobuf message from a byte slice
msg, err := dynamic.AsDynamicMessage([]byte{...})
if err != nil {
    // handle error
}

// Access the message fields
fmt.Println(msg.GetFieldByName("name").GetStringValue())
  1. Generating Protobuf Code:
import (
    "github.com/jhump/protoreflect/desc/protoparse"
    "github.com/jhump/protoreflect/desc/protoprint"
)

// Parse a protobuf file
fileDesc, err := protoparse.Parser{}.ParseFile("example.proto")
if err != nil {
    // handle error
}

// Generate Go code from the file descriptor
goCode, err := protoprint.PrintProtoAsGoCode(fileDesc)
if err != nil {
    // handle error
}

// Print the generated Go code
fmt.Println(goCode)
  1. Manipulating Protobuf Messages:
import (
    "github.com/jhump/protoreflect/dynamic"
)

// Create a new protobuf message
msg := dynamic.NewMessage(&desc.MessageDescriptor{})

// Set a field value
msg.SetFieldByName("name", "John Doe")

// Serialize the message to bytes
bytes, err := msg.Marshal()
if err != nil {
    // handle error
}
  1. Reflecting on Protobuf Descriptors:
import (
    "fmt"
    "github.com/jhump/protoreflect/desc"
)

// Load a protobuf file descriptor
fileDesc, err := desc.LoadFileDescriptor("example.proto")
if err != nil {
    // handle error
}

// Iterate over the message descriptors
for _, msgDesc := range fileDesc.GetMessageTypes() {
    fmt.Println(msgDesc.GetName())
}

Getting Started

To get started with the jhump/protoreflect library, follow these steps:

  1. Install the library using Go's package manager:
go get github.com/jhump/protoreflect
  1. Import the necessary packages in your Go code:
import (

Competitor Comparisons

[Deprecated] Protocol Buffers for Go with Gadgets

Pros of gogo/protobuf

  • Offers significant performance improvements and optimizations over standard protobuf
  • Provides additional code generation options and customization features
  • Supports custom types and extensions for enhanced flexibility

Cons of gogo/protobuf

  • Less actively maintained compared to protoreflect
  • May have compatibility issues with newer protobuf versions
  • Steeper learning curve due to additional features and complexity

Code Comparison

protoreflect:

message := &myproto.MyMessage{}
err := proto.Unmarshal(data, message)
if err != nil {
    return err
}

gogo/protobuf:

message := &myproto.MyMessage{}
err := message.Unmarshal(data)
if err != nil {
    return err
}

Summary

protoreflect focuses on reflection capabilities and compatibility with standard protobuf, while gogo/protobuf emphasizes performance optimizations and additional features. protoreflect is more actively maintained and aligns closely with the official protobuf implementation. gogo/protobuf offers performance benefits but may require more effort to integrate and maintain in projects.

Choose protoreflect for better long-term support and standard compatibility, or gogo/protobuf for performance-critical applications willing to trade some compatibility for speed.

Go support for Google's protocol buffers

Pros of protobuf-go

  • Official implementation by Google, ensuring compatibility and regular updates
  • Optimized performance for Go-specific use cases
  • Seamless integration with other Google Cloud services and tools

Cons of protobuf-go

  • Limited flexibility for advanced use cases and custom modifications
  • Stricter adherence to Protocol Buffers specification, potentially limiting some Go-specific optimizations

Code Comparison

protobuf-go:

import "google.golang.org/protobuf/proto"

func main() {
    message := &MyMessage{...}
    data, err := proto.Marshal(message)
}

protoreflect:

import "github.com/jhump/protoreflect/dynamic"

func main() {
    message := dynamic.NewMessage(messageDescriptor)
    data, err := message.Marshal()
}

protobuf-go provides a more straightforward API for basic Protocol Buffers operations, while protoreflect offers greater flexibility and reflection capabilities. protobuf-go is ideal for standard use cases and integration with Google services, whereas protoreflect is better suited for advanced scenarios requiring dynamic message handling or custom Protocol Buffers implementations.

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

Pros of protoc-gen-validate

  • Focused specifically on generating validation code for Protocol Buffers
  • Supports multiple programming languages (Go, Java, Python, etc.)
  • Provides a rich set of validation rules and constraints

Cons of protoc-gen-validate

  • Limited to validation functionality only
  • Requires additional setup and integration with the protoc compiler
  • May have a steeper learning curve for complex validation scenarios

Code Comparison

protoc-gen-validate:

message User {
  string email = 1 [(validate.rules).string.email = true];
  int32 age = 2 [(validate.rules).int32 = {gte: 18, lte: 99}];
}

protoreflect:

import "github.com/jhump/protoreflect/desc"

func validateUser(user *User) error {
    md, _ := desc.LoadMessageDescriptorForMessage(user)
    // Custom validation logic using reflection
}

Summary

protoc-gen-validate is a specialized tool for generating validation code for Protocol Buffers, supporting multiple languages and offering a rich set of validation rules. It's ideal for projects requiring strict data validation but may have a steeper learning curve.

protoreflect, on the other hand, provides a more general-purpose reflection API for Protocol Buffers in Go. It offers greater flexibility for custom operations but requires more manual implementation for validation tasks.

Choose protoc-gen-validate for streamlined, multi-language validation generation, or protoreflect for broader Protocol Buffer manipulation capabilities in Go.

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

Protocol Buffer and gRPC Reflection

Build Status Go Report Card

This repo provides reflection APIs for protocol buffers (also known as "protobufs" for short) and gRPC. The core of reflection in protobufs is the descriptor. A descriptor is itself a protobuf message that describes a .proto source file or any element therein. So a collection of descriptors can describe an entire schema of protobuf types, including RPC services.

GoDoc

[!IMPORTANT] This repo was originally built to work with the "V1" API of the Protobuf runtime for Go: github.com/golang/protobuf.

Since the creation of this repo, a new runtime for Go has been released, a "V2" of the API in google.golang.org/protobuf. This newer API now includes support for functionality that this repo implements:

Most protobuf users have certainly upgraded to that newer runtime by now and thus encounter some friction using this repo. It is now recommended to use the above packages in the V2 Protobuf API instead of using the corresponding packages in this repo. But that still leaves a lot of functionality in this repo, such as the desc/builder, desc/protoparse, desc/protoprint, dynamic/grpcdynamic, dynamic/msgregistry, and grpcreflect packages herein. And all of these packages build on the core desc.Descriptor types in this repo. As of v1.15.0, you can convert between this repo's desc.Descriptor types and the V2 API's protoreflect.Descriptor types using Wrap functions in the desc package and Unwrap methods on the desc.Descriptor types. That allows easier interop between these remaining useful packages and new V2 API descriptor implementations.

If you have code that uses the dynamic package in this repo and are trying to interop with V2 APIs, in some cases you can use the proto.MessageV2 converter function (defined in the V1 proto package in github.com/golang/protobuf/proto). However, this wrapper does not provide 100% complete interop, so in some cases you may have to port your code over to the V2 API's dynamicpb package. (Sorry!)

[!NOTE] We've had a v2 of this whole repo in the works for some time. A lot of what's in this repo is no longer necessary, but some features still are. The v2 will drop functionality now provided by the V2 Protobuf API. The remaining packages will be updated to make direct use of the V2 Protobuf API and have no more references to the old V1 API. One exception is that a v2 of this repo will not include a new version of the desc/protoparse package in this repo -- that is already available in a brand new module named protocompile.

If you want to try out the v2, you can do so by getting a pre-release version:

go get github.com/jhump/protoreflect/v2@c9ae7caed596cda2e3c4a90f5973a46081a371a

Note that the APIs are likely to change a little bit between now and a formal v2 release. Also note that some packages in the v2 still need more tests, so you may find some bugs, but that is mostly for new functionality. If you're just trying to update your code from v1 of this repo, those packages should be rock-solid and least likely to see any further API changes.

Descriptors: The Language Model of Protocol Buffers

import "github.com/jhump/protoreflect/desc"

The desc package herein introduces a Descriptor interface and implementations of it that correspond to each of the descriptor types. These new types are effectively smart wrappers around the generated protobuf types that make them much more useful and easier to use.

You can construct descriptors from file descriptor sets (which can be generated by protoc), and you can also load descriptors for messages and services that are linked into the current binary. "What does it mean for messages and services to be linked in?" you may ask. It means your binary imports a package that was generated by protoc. When you generate Go code from your .proto sources, the resulting package has descriptor information embedded in it. The desc package allows you to easily extract those embedded descriptors.

Descriptors can also be acquired directly from .proto source files (using the protoparse sub-package) or by programmatically constructing them (using the builder sub-package).

Read more ≫

import "github.com/jhump/protoreflect/desc/protoparse"

The protoparse package allows for parsing of .proto source files into rich descriptors. Without this package, you must invoke protoc to either generate a file descriptor set file or to generate Go code (which has descriptor information embedded in it). This package allows reading the source directly without having to invoke protoc.

Read more ≫

import "github.com/jhump/protoreflect/desc/protoprint"

The protoprint package allows for printing of descriptors to .proto source files. This is effectively the inverse of the protoparse package. Combined with the builder package, this is a useful tool for programmatically generating protocol buffer sources.

Read more ≫

import "github.com/jhump/protoreflect/desc/builder"

The builder package allows for programmatic construction of rich descriptors. Descriptors can be constructed programmatically by creating trees of descriptor protos and using the desc package to link those into rich descriptors. But constructing a valid tree of descriptor protos is far from trivial.

So this package provides generous API to greatly simplify that task. It also allows for converting rich descriptors into builders, which means you can programmatically modify/tweak existing descriptors.

Read more ≫


Dynamic Messages and Stubs

import "github.com/jhump/protoreflect/dynamic"

The dynamic package provides a dynamic message implementation. It implements proto.Message but is backed by a message descriptor and a map of fields->values, instead of a generated struct. This is useful for acting generically with protocol buffer messages, without having to generate and link in Go code for every kind of message. This is particularly useful for general-purpose tools that need to operate on arbitrary protocol buffer schemas. This is made possible by having the tools load descriptors at runtime.

Read more ≫

import "github.com/jhump/protoreflect/dynamic/grpcdynamic"

There is also sub-package named grpcdynamic, which provides a dynamic stub implementation. The stub can be used to issue RPC methods using method descriptors instead of generated client interfaces.

Read more ≫


gRPC Server Reflection

import "github.com/jhump/protoreflect/grpcreflect"

The grpcreflect package provides an easy-to-use client for the gRPC reflection service, making it much easier to query for and work with the schemas of remote services.

It also provides some helper methods for querying for rich service descriptors for the services registered in a gRPC server.

Read more ≫