Documentation
¶
Overview ¶
Package proto provides Protocol Buffers binding support for the binding package.
This package extends rivaas.dev/binding with Protocol Buffers serialization support, using google.golang.org/protobuf for parsing.
Example:
// Assuming you have generated proto code:
// message User {
// string name = 1;
// int32 age = 2;
// }
user, err := proto.Proto[*pb.User](body)
if err != nil {
// handle error
}
Index ¶
- func FromProto(body []byte, opts ...Option) binding.Option
- func FromProtoReader(r io.Reader, opts ...Option) binding.Option
- func Proto[T Message](body []byte, opts ...Option) (T, error)
- func ProtoReader[T Message](r io.Reader, opts ...Option) (T, error)
- func ProtoReaderTo(r io.Reader, out Message, opts ...Option) error
- func ProtoTo(body []byte, out Message, opts ...Option) error
- type Message
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FromProto ¶
FromProto returns a binding.Option that specifies Protocol Buffers body as a binding source. This can be used with binding.Bind for multi-source binding.
Note: When using FromProto, you need to ensure the target struct implements proto.Message.
Example:
req, err := binding.Bind[*pb.Request](
binding.FromQuery(r.URL.Query()),
proto.FromProto(body),
)
func FromProtoReader ¶
FromProtoReader returns a binding.Option that specifies Protocol Buffers from io.Reader as a binding source.
Example:
req, err := binding.Bind[*pb.Request](
proto.FromProtoReader(r.Body),
)
func Proto ¶
Proto binds Protocol Buffers bytes to type T. T must implement proto.Message.
Example:
user, err := proto.Proto[*pb.User](body) // With options user, err := proto.Proto[*pb.User](body, proto.WithDiscardUnknown())
Example ¶
ExampleProto demonstrates basic Protocol Buffers binding.
package main
import (
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create a test user message
user := &testdata.User{
Name: "John",
Email: "john@example.com",
Age: 30,
Active: true,
}
// Marshal to proto bytes (simulating incoming request)
body, err := goproto.Marshal(user)
if err != nil {
log.Fatal(err)
}
// Bind using the proto package
result, err := proto.Proto[*testdata.User](body)
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Name: %s, Email: %s, Age: %d, Active: %v\n", result.GetName(), result.GetEmail(), result.GetAge(), result.GetActive())
}
Output: Name: John, Email: john@example.com, Age: 30, Active: true
Example (MapFields) ¶
ExampleProto_mapFields demonstrates binding Protocol Buffers map fields.
package main
import (
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create settings with a map field
settings := &testdata.Settings{
Name: "AppSettings",
Metadata: map[string]string{
"version": "1.0.0",
"environment": "production",
},
}
// Marshal to proto bytes
body, err := goproto.Marshal(settings)
if err != nil {
log.Fatal(err)
}
// Bind the map fields
result, err := proto.Proto[*testdata.Settings](body)
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Settings: %s\n", result.GetName())
_, _ = fmt.Printf("Version: %s\n", result.GetMetadata()["version"])
_, _ = fmt.Printf("Environment: %s\n", result.GetMetadata()["environment"])
}
Output: Settings: AppSettings Version: 1.0.0 Environment: production
Example (MultipleOptions) ¶
ExampleProto_multipleOptions demonstrates using multiple options together.
package main
import (
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create a test user message
user := &testdata.User{
Name: "Diana",
Email: "diana@example.com",
Age: 32,
Active: true,
}
// Marshal to proto bytes
body, err := goproto.Marshal(user)
if err != nil {
log.Fatal(err)
}
// Bind with multiple options
result, err := proto.Proto[*testdata.User](body,
proto.WithAllowPartial(),
proto.WithDiscardUnknown(),
proto.WithRecursionLimit(5000),
)
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Name: %s, Age: %d\n", result.GetName(), result.GetAge())
}
Output: Name: Diana, Age: 32
Example (NestedMessages) ¶
ExampleProto_nestedMessages demonstrates binding nested Protocol Buffers messages.
package main
import (
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create a nested config message
config := &testdata.Config{
Title: "Production Config",
Server: &testdata.Server{
Host: "0.0.0.0",
Port: 8080,
},
Database: &testdata.Database{
Host: "db.example.com",
Port: 5432,
Name: "mydb",
User: "admin",
Password: "secret",
},
}
// Marshal to proto bytes
body, err := goproto.Marshal(config)
if err != nil {
log.Fatal(err)
}
// Bind the nested structure
result, err := proto.Proto[*testdata.Config](body)
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Title: %s\n", result.GetTitle())
_, _ = fmt.Printf("Server: %s:%d\n", result.GetServer().GetHost(), result.GetServer().GetPort())
_, _ = fmt.Printf("Database: %s@%s:%d\n", result.GetDatabase().GetName(), result.GetDatabase().GetHost(), result.GetDatabase().GetPort())
}
Output: Title: Production Config Server: 0.0.0.0:8080 Database: mydb@db.example.com:5432
Example (RepeatedFields) ¶
ExampleProto_repeatedFields demonstrates binding repeated Protocol Buffers fields.
package main
import (
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create a product with repeated fields
product := &testdata.Product{
Name: "Widget",
Tags: []string{"electronics", "gadget", "sale"},
Prices: []int32{100, 150, 200},
}
// Marshal to proto bytes
body, err := goproto.Marshal(product)
if err != nil {
log.Fatal(err)
}
// Bind the repeated fields
result, err := proto.Proto[*testdata.Product](body)
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Product: %s\n", result.GetName())
_, _ = fmt.Printf("Tags: %v\n", result.GetTags())
_, _ = fmt.Printf("Prices: %v\n", result.GetPrices())
}
Output: Product: Widget Tags: [electronics gadget sale] Prices: [100 150 200]
Example (WithDiscardUnknown) ¶
ExampleProto_withDiscardUnknown demonstrates binding with unknown field handling.
package main
import (
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create a test user message
user := &testdata.User{
Name: "Bob",
Email: "bob@example.com",
Age: 35,
Active: false,
}
// Marshal to proto bytes
body, err := goproto.Marshal(user)
if err != nil {
log.Fatal(err)
}
// Bind with DiscardUnknown option
result, err := proto.Proto[*testdata.User](body, proto.WithDiscardUnknown())
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Name: %s, Active: %v\n", result.GetName(), result.GetActive())
}
Output: Name: Bob, Active: false
func ProtoReader ¶
ProtoReader binds Protocol Buffers from an io.Reader to type T. T must implement proto.Message.
Example:
user, err := proto.ProtoReader[*pb.User](r.Body)
Example ¶
ExampleProtoReader demonstrates Protocol Buffers binding from io.Reader.
package main
import (
"bytes"
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create a test user message
user := &testdata.User{
Name: "Alice",
Email: "alice@example.com",
Age: 25,
Active: true,
}
// Marshal to proto bytes
body, err := goproto.Marshal(user)
if err != nil {
log.Fatal(err)
}
// Bind from io.Reader
result, err := proto.ProtoReader[*testdata.User](bytes.NewReader(body))
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Name: %s, Email: %s\n", result.GetName(), result.GetEmail())
}
Output: Name: Alice, Email: alice@example.com
func ProtoReaderTo ¶
ProtoReaderTo binds Protocol Buffers from an io.Reader to out. out must implement proto.Message.
Example:
var user pb.User err := proto.ProtoReaderTo(r.Body, &user)
func ProtoTo ¶
ProtoTo binds Protocol Buffers bytes to out. out must implement proto.Message.
Example:
var user pb.User err := proto.ProtoTo(body, &user)
Example ¶
ExampleProtoTo demonstrates non-generic Protocol Buffers binding.
package main
import (
"fmt"
"log"
"rivaas.dev/binding/proto"
"rivaas.dev/binding/proto/testdata"
goproto "google.golang.org/protobuf/proto"
)
func main() {
// Create a test config message
config := &testdata.Config{
Title: "My App",
Server: &testdata.Server{
Host: "localhost",
Port: 8080,
},
}
// Marshal to proto bytes
body, err := goproto.Marshal(config)
if err != nil {
log.Fatal(err)
}
// Bind using the non-generic function
var result testdata.Config
err = proto.ProtoTo(body, &result)
if err != nil {
log.Fatal(err)
}
_, _ = fmt.Printf("Title: %s, Server: %s:%d\n", result.GetTitle(), result.GetServer().GetHost(), result.GetServer().GetPort())
}
Output: Title: My App, Server: localhost:8080
Types ¶
type Option ¶
type Option func(*config)
Option configures Protocol Buffers binding behavior.
func WithAllowPartial ¶
func WithAllowPartial() Option
WithAllowPartial allows messages that have missing required fields to unmarshal without returning an error.
func WithDiscardUnknown ¶
func WithDiscardUnknown() Option
WithDiscardUnknown specifies whether to ignore unknown fields when unmarshaling.
func WithRecursionLimit ¶
WithRecursionLimit sets the maximum recursion depth for unmarshaling. The default limit is 10,000.