pbtype-server

module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2024 License: MIT

README

A Protobuf Type Server

Go Documentation GitHub Tag

A type server for protobuf file descriptors mainly used to work with google.protobuf.Any when pre-compiling the the proto files into the final binary is not acceptable or impossible.

The type-server implements a Connect-RPC/gRPC interface similar to the gRPC Server-Reflection and is defined in tierklinik-dobersberg/apis.

It also includes support for protobuf well-known types (google/protobuf/*).

Usage

Just start the type-server binary and configure all protobuf sources that should be served using the command line flags --source. pbtype-server will automaticall re-fetch the protobuf sources ever 10 minutes. To configure the interval, use the --interval <duration> flag.

go build ./cmds/pbtype-server

./pbtype-server --interval 10m \
    --source github.com/tierklinik-dobersberg/apis.git//proto \
    --source github.com/bufbuild/protovalidate.git//proto/protovalidate

Sources are downloaded using the awesome hashicorp/go-getter library which supports downloading from various sources and supports automatic unpacking of archives. Refer to it's documentation on how to specify URLs.

Client Library

This package also provides a simple Go client library for fetching protobuf type definitions:

package main

import (
    "log"

    "github.com/tierklinik-dobersberg/pbtype-server/pkg/resolver"
    "github.com/tierklinik-dobersberg/pbtype-server/pkg/protoresolve"

    "google.golang.org/protobuf/reflect/protoreflect"
    "google.golang.org/protobuf/types/dynamicpb"
    "google.golang.org/protobuf/encoding/protojson"
    "google.golang.org/protobuf/reflect/protoregistry"
)

// The address of your type-server
const server = "https://types.dobersberg.vet"

func main() {
    resolver := resolver.New(server)

    // Find a message descriptor by it's fully qualified name
    desc, err := resolver.FindDescriptorByName("google.protobuf.Duration")
    if err != nil {
        log.Fatalf("failed to find descriptor: %s", err)
    }

    messageDescriptor, ok := desc.(protoreflect.MessageDescriptor)
    if !ok {
        log.Fatalf("expected a message descriptor but got %T", desc)
    }

    // do something with messageDescriptor
    // for example, create a new message using dynamicpb
    msg := dynamicpb.NewMessage(messageDescriptor)


    // Instead of using dynamicpb, one can also directly use NewMessage or NewMessageFromBytes
    msg, err := resolver.NewMessage("google.protobuf.Timestamp")


    // Also, resolver.Resolver implements protodesc.Resolver, protoreflect.MessageTypeResolver and protoreflect.ExtensionTypeResolver
    // so it's easy to use protojson on unknown types by specifying a custom resolver:
    encoder := &protojson.MarshalOptions{
        Resolver: resolver,
    }

    // The resolver will now query the type server if msg is unknown
    blob, err := encoder.Marshal(msg)

    // Instead of using resolver.New, which uses a new File and Type registry, it
    // is also possible to wrap protoregistry.GlobalFiles and protoregistry.GlobalTypes.
    // This way, all descriptors fetched by the resolver will be persisted in the 
    // global protoregistry.
    resolver := resolver.Wrap(
        server,
        protoregistry.GlobalFiles,
        protoregistry.GlobalTypes,
    ) 

    // If you don't want to populate/store descriptors in the global protoregistry
    // but still want your pre-compiled protobuf files to be available in the resolver
    // you can use the provided protoresolve package:

    encoder = &protojson.MarshalOptions{
        // Use a combined resolver which will query each resolver in order until
        // one is able to find the requested descriptor.
        // In this example, the pre-compiled proto files will be queries first
        // and only if no descriptor is found the resolver will ask the type-server.
        Resolver: protoresolve.NewCombinedResolver(
            protoresolve.NewGlobalResolver(), // provides access to protoregistry.GlobalFiles and protoregistry.GlobalTypes,
            resolver.New(server),
        ),
    }
}

Directories

Path Synopsis
cmds
internal
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL