Documentation
¶
Overview ¶
Package grpcreflect enables any net/http server, including those built with Connect, to handle gRPC's server reflection API. This lets ad-hoc debugging tools call your Protobuf services and print the responses without a copy of the schema.
The exposed reflection API is wire compatible with Google's gRPC implementations, so it works with grpcurl, grpcui, BloomRPC, and many other tools.
The core Connect package is connectrpc.com/connect. Documentation is available at https://connectrpc.com.
Index ¶
- Constants
- func IsReflectionStreamBroken(err error) bool
- func NewHandlerV1(reflector *Reflector, options ...connect.HandlerOption) (string, http.Handler)
- func NewHandlerV1Alpha(reflector *Reflector, options ...connect.HandlerOption) (string, http.Handler)
- type Client
- type ClientStream
- func (cs *ClientStream) AllExtensionNumbers(messageName protoreflect.FullName) ([]protoreflect.FieldNumber, error)
- func (cs *ClientStream) Close() (http.Header, error)
- func (cs *ClientStream) FileByFilename(filename string) ([]*descriptorpb.FileDescriptorProto, error)
- func (cs *ClientStream) FileContainingExtension(messageName protoreflect.FullName, extensionNumber protoreflect.FieldNumber) ([]*descriptorpb.FileDescriptorProto, error)
- func (cs *ClientStream) FileContainingSymbol(name protoreflect.FullName) ([]*descriptorpb.FileDescriptorProto, error)
- func (cs *ClientStream) ListServices() ([]protoreflect.FullName, error)
- func (cs *ClientStream) Peer() connect.Peer
- func (cs *ClientStream) ResponseHeader() http.Header
- func (cs *ClientStream) Spec() connect.Spec
- type ClientStreamOption
- type ExtensionResolver
- type Namer
- type NamerFunc
- type Option
- type Reflector
Examples ¶
Constants ¶
const ( // ReflectV1ServiceName is the fully-qualified name of the v1 version of the reflection service. ReflectV1ServiceName = "grpc.reflection.v1.ServerReflection" // ReflectV1AlphaServiceName is the fully-qualified name of the v1alpha version of the reflection service. ReflectV1AlphaServiceName = "grpc.reflection.v1alpha.ServerReflection" )
Variables ¶
This section is empty.
Functions ¶
func IsReflectionStreamBroken ¶ added in v1.1.0
IsReflectionStreamBroken returns true if the given error was the result of a ClientStream failing. If the stream returns an error for which this function returns false, only the one operation failed; the stream is still intact and may be used for subsequent operations.
func NewHandlerV1 ¶
NewHandlerV1 constructs an implementation of v1 of the gRPC server reflection API. It returns an HTTP handler and the path on which to mount it.
Note that because the reflection API requires bidirectional streaming, the returned handler doesn't support HTTP/1.1. If your server must also support older tools that use the v1alpha server reflection API, see NewHandlerV1Alpha.
func NewHandlerV1Alpha ¶
func NewHandlerV1Alpha(reflector *Reflector, options ...connect.HandlerOption) (string, http.Handler)
NewHandlerV1Alpha constructs an implementation of v1alpha of the gRPC server reflection API, which is useful to support tools that haven't updated to the v1 API. It returns an HTTP handler and the path on which to mount it.
Like NewHandlerV1, the returned handler doesn't support HTTP/1.1.
Types ¶
type Client ¶ added in v1.1.0
type Client struct {
// contains filtered or unexported fields
}
Client is a Connect client for the server reflection service.
func NewClient ¶ added in v1.1.0
func NewClient(httpClient connect.HTTPClient, baseURL string, options ...connect.ClientOption) *Client
NewClient returns a client for interacting with the gRPC server reflection service. The given HTTP client, base URL, and options are used to connect to the service.
This client will try "v1" of the service first (grpc.reflection.v1.ServerReflection). If this results in a "Not Implemented" error, the client will fall back to "v1alpha" of the service (grpc.reflection.v1alpha.ServerReflection).
Example ¶
package main import ( "context" "fmt" "log" "net/http" "connectrpc.com/grpcreflect" ) func main() { // Create a client to the Connect demo server. client := grpcreflect.NewClient(http.DefaultClient, "https://demo.connectrpc.com") // Create a new reflection stream. stream := client.NewStream(context.Background()) // Ask the server for its services and for the file descriptor that contains the first one. names, err := stream.ListServices() if err != nil { log.Printf("error listing services: %v", err) return } fmt.Printf("services: %v\n", names) files, err := stream.FileContainingSymbol(names[0]) if err != nil { log.Printf("error getting file that contains %q: %v", names[0], err) return } fmt.Printf("file descriptor for %q\n", files[len(files)-1].GetName()) }
Output: services: [connectrpc.eliza.v1.ElizaService] file descriptor for "connectrpc/eliza/v1/eliza.proto"
func (*Client) NewStream ¶ added in v1.1.0
func (c *Client) NewStream(ctx context.Context, options ...ClientStreamOption) *ClientStream
NewStream creates a new stream that is used to download reflection information from the server. This is a bidirectional stream, so can only be successfully used over HTTP/2. The ClientStream.Close method should be called when the caller is done with the stream.
If any operation returns an error for which IsReflectionStreamBroken returns true, the stream is broken and all subsequent operations will fail. If the error is not a permanent error, the caller should create another stream and try again.
type ClientStream ¶ added in v1.1.0
type ClientStream struct {
// contains filtered or unexported fields
}
ClientStream represents a bidirectional stream for downloading reflection information. The reflection protocol resembles a sequence of unary RPCs: multiple requests sent on the stream, each getting back a corresponding response. However, all such requests and responses and sent on a single stream to a single server, to ensure consistency in the information downloaded (since different servers could potentially have different versions of reflection information).
func (*ClientStream) AllExtensionNumbers ¶ added in v1.1.0
func (cs *ClientStream) AllExtensionNumbers(messageName protoreflect.FullName) ([]protoreflect.FieldNumber, error)
AllExtensionNumbers retrieves the tag numbers for all extensions of the given message that are known to the server.
This may return a *connect.Error indicating the reason the list of extension numbers could not be retrieved (such as "Not Found" if the given message is not known). But if IsReflectionStreamBroken returns true for the returned error, the stream is broken and cannot be used for further operations.
This operation sends a request message on the stream and waits for the corresponding response.
func (*ClientStream) Close ¶ added in v1.1.0
func (cs *ClientStream) Close() (http.Header, error)
Close closes the stream and returns any trailers sent by the server.
func (*ClientStream) FileByFilename ¶ added in v1.1.0
func (cs *ClientStream) FileByFilename(filename string) ([]*descriptorpb.FileDescriptorProto, error)
FileByFilename retrieves the descriptor for the file with the given path and name. The server may respond with multiple files, which represent the request file plus its imports or full transitive dependency graph. If the server has already sent back some of those files on this stream, they may be omitted from the response.
This may return a *connect.Error indicating the reason the file could not be retrieved (such as "Not Found" if the given path is not known). But if IsReflectionStreamBroken returns true for the returned error, the stream is broken and cannot be used for further operations.
This operation sends a request message on the stream and waits for the corresponding response.
func (*ClientStream) FileContainingExtension ¶ added in v1.1.0
func (cs *ClientStream) FileContainingExtension(messageName protoreflect.FullName, extensionNumber protoreflect.FieldNumber) ([]*descriptorpb.FileDescriptorProto, error)
FileContainingExtension retrieves the descriptor for the file that defines the extension with the given tag number and for the given extendable message. The server may respond with multiple files, which represent not only the file containing the requested symbol but also its imports or full transitive dependency graph. If the server has already sent back some of those files on this stream, they may be omitted from the response.
This may return a *connect.Error indicating the reason the file could not be retrieved (such as "Not Found" if the given extension is not known). But if IsReflectionStreamBroken returns true for the returned error, the stream is broken and cannot be used for further operations.
This operation sends a request message on the stream and waits for the corresponding response.
func (*ClientStream) FileContainingSymbol ¶ added in v1.1.0
func (cs *ClientStream) FileContainingSymbol(name protoreflect.FullName) ([]*descriptorpb.FileDescriptorProto, error)
FileContainingSymbol retrieves the descriptor for the file that defines the element with the given fully-qualified name. The server may respond with multiple files, which represent not only the file containing the requested symbol but also its imports or full transitive dependency graph. If the server has already sent back some of those files on this stream, they may be omitted from the response.
This may return a *connect.Error indicating the reason the file could not be retrieved (such as "Not Found" if the given element is not known). But if IsReflectionStreamBroken returns true for the returned error, the stream is broken and cannot be used for further operations.
This operation sends a request message on the stream and waits for the corresponding response.
func (*ClientStream) ListServices ¶ added in v1.1.0
func (cs *ClientStream) ListServices() ([]protoreflect.FullName, error)
ListServices retrieves the fully-qualified names for services exposed the server.
This may return a *connect.Error indicating the reason the list of services could not be retrieved. But if IsReflectionStreamBroken returns true for the returned error, the stream is broken and cannot be used for further operations.
This operation sends a request message on the stream and waits for the corresponding response.
func (*ClientStream) Peer ¶ added in v1.1.0
func (cs *ClientStream) Peer() connect.Peer
Peer describes the server for the RPC.
func (*ClientStream) ResponseHeader ¶ added in v1.1.0
func (cs *ClientStream) ResponseHeader() http.Header
ResponseHeader returns the headers received from the server. It blocks until the response headers have been sent by the server.
It is possible that the server implementation won't send back response headers until after it receives the first request message, sending back headers along with the first response message. So it is safest to either call this method from a different goroutine than the one that invokes other stream operations or to not call this until after the first such operation has completed.
The operations that send a message on the stream are [ListServices], [FileByFilename], [FileContainingSymbol], [FileContainingExtension], and [AllExtensionNumbers].
func (*ClientStream) Spec ¶ added in v1.1.0
func (cs *ClientStream) Spec() connect.Spec
Spec returns the specification for the reflection RPC.
type ClientStreamOption ¶ added in v1.1.0
type ClientStreamOption interface {
// contains filtered or unexported methods
}
ClientStreamOption is an option that can be provided when calling Client.NewStream.
func WithReflectionHost ¶ added in v1.1.0
func WithReflectionHost(host string) ClientStreamOption
WithReflectionHost is an option that allows the caller to provide the hostname that will be included with all requests on the stream. This may be used by the server when deciding what source of reflection information to use (which could include forwarding the request message to a different host).
func WithRequestHeaders ¶ added in v1.1.0
func WithRequestHeaders(headers http.Header) ClientStreamOption
WithRequestHeaders is an option that allows the caller to provide the request headers that will be sent when a stream is created.
type ExtensionResolver ¶
type ExtensionResolver interface { protoregistry.ExtensionTypeResolver RangeExtensionsByMessage(protoreflect.FullName, func(protoreflect.ExtensionType) bool) }
An ExtensionResolver lets server reflection implementations query details about the registered Protobuf extensions. protoregistry.GlobalTypes implements ExtensionResolver.
ExtensionResolvers must be safe to call concurrently.
type Namer ¶
type Namer interface {
Names() []string
}
A Namer lists the fully-qualified Protobuf service names available for reflection (for example, "acme.user.v1.UserService"). Namers must be safe to call concurrently.
type NamerFunc ¶ added in v1.3.0
type NamerFunc func() []string
NamerFunc is an adapter to allow the use of an ordinary function as a Namer. Example:
reflector := grpcreflect.NewReflector(grpcreflect.NamerFunc( func() []string { return s.names }, ))
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
An Option configures a Reflector.
func WithDescriptorResolver ¶
WithDescriptorResolver sets the resolver used to find Protobuf type information (typically called a "descriptor"). By default, Reflectors use protoregistry.GlobalFiles.
func WithExtensionResolver ¶
func WithExtensionResolver(resolver ExtensionResolver) Option
WithExtensionResolver sets the resolver used to find Protobuf extensions. By default, Reflectors use protoregistry.GlobalTypes.
type Reflector ¶
type Reflector struct {
// contains filtered or unexported fields
}
Reflector implements the underlying logic for gRPC's protobuf server reflection. They're configurable, so they can support straightforward process-local reflection or more complex proxying.
Keep in mind that by default, Reflectors expose every protobuf type and extension compiled into your binary. Think twice before including the default Reflector in a public API.
For more information, see https://github.com/grpc/grpc-go/blob/master/Documentation/server-reflection-tutorial.md, https://github.com/grpc/grpc/blob/master/doc/server-reflection.md, and https://github.com/fullstorydev/grpcurl.
func NewReflector ¶
NewReflector constructs a highly configurable Reflector: it can serve a dynamic list of services, proxy reflection requests to other backends, or use an alternate source of extension information.
To build a simpler Reflector that supports a static list of services using information from the package-global Protobuf registry, use NewStaticReflector.
func NewStaticReflector ¶
NewStaticReflector constructs a simple Reflector that supports a static list of services using information from the package-global Protobuf registry. For a more configurable Reflector, use NewReflector.
The supplied strings should be fully-qualified Protobuf service names (for example, "acme.user.v1.UserService"). Generated Connect service files have this declared as a constant.