Documentation ¶
Overview ¶
Package vanguard provides a transcoder that acts like middleware for your RPC handlers, augmenting them to support additional protocols or message formats, including REST+JSON. The transcoder also acts as a router, handling dispatch of configured REST-ful URI paths to the right RPC handlers.
Use NewService or NewServiceWithSchema to create Service definitions wrap your existing HTTP and/or RPC handlers. Then pass those services to NewTranscoder.
Example (RestClientToRpcServer) ¶
package main import ( "bytes" "context" "io" "log" "net/http" "net/http/httptest" "os" "strings" "time" "connectrpc.com/connect" "connectrpc.com/vanguard" testv1 "connectrpc.com/vanguard/internal/gen/vanguard/test/v1" "connectrpc.com/vanguard/internal/gen/vanguard/test/v1/testv1connect" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/types/known/timestamppb" ) func main() { // This example shows Vanguard adding REST support to an RPC server built // with Connect. (To add REST, gRPC-Web, and Connect support to servers built // with grpc-go, use the connectrpc.com/vanguard/vanguardgrpc sub-package.) logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */) // libraryRPC is an implementation of the testv1connect.LibraryService RPC // server. It's a pure RPC server, without any hand-written translation to or // from RESTful semantics. svc := &libraryRPC{} rpcRoute, rpcHandler := testv1connect.NewLibraryServiceHandler(svc) // Using Vanguard, the server can also accept RESTful requests. The Vanguard // Transcoder handles both REST and RPC traffic, so there's no need to mount // the RPC-only handler. services := []*vanguard.Service{vanguard.NewService(rpcRoute, rpcHandler)} transcoder, err := vanguard.NewTranscoder(services) if err != nil { logger.Println(err) return } // We can use any server that works with http.Handlers. Since this is a // testable example, we're using httptest. server := httptest.NewServer(transcoder) defer server.Close() // With the server running, we can make a RESTful call. client := server.Client() book := &testv1.Book{ Title: "2001: A Space Odyssey", Author: "Arthur C. Clarke", Description: "A space voyage to Jupiter awakens the crew's intelligence.", Labels: map[string]string{ "genre": "science fiction", }, } body, err := protojson.Marshal(book) if err != nil { logger.Println(err) return } req, err := http.NewRequestWithContext( context.Background(), http.MethodPost, server.URL+"/v1/shelves/top/books", bytes.NewReader(body), ) if err != nil { logger.Println(err) return } req.Header.Set("Content-Type", "application/json") req.URL.RawQuery = "book_id=2&request_id=123" rsp, err := client.Do(req) if err != nil { logger.Println(err) return } defer rsp.Body.Close() logger.Println(rsp.Status) logger.Println(rsp.Header.Get("Content-Type")) body, err = io.ReadAll(rsp.Body) if err != nil { logger.Println(err) return } if err := protojson.Unmarshal(body, book); err != nil { logger.Println(err) return } logger.Println(book.GetAuthor()) } type libraryRPC struct { testv1connect.UnimplementedLibraryServiceHandler } func (s *libraryRPC) GetBook(_ context.Context, req *connect.Request[testv1.GetBookRequest]) (*connect.Response[testv1.Book], error) { msg := req.Msg rsp := connect.NewResponse(&testv1.Book{ Name: msg.GetName(), Parent: strings.Join(strings.Split(msg.GetName(), "/")[:2], "/"), CreateTime: timestamppb.New(time.Date(1968, 1, 1, 0, 0, 0, 0, time.UTC)), Title: "Do Androids Dream of Electric Sheep?", Author: "Philip K. Dick", Description: "Have you seen Blade Runner?", Labels: map[string]string{ "genre": "science fiction", }, }) return rsp, nil } func (s *libraryRPC) CreateBook(_ context.Context, req *connect.Request[testv1.CreateBookRequest]) (*connect.Response[testv1.Book], error) { msg := req.Msg book := req.Msg.GetBook() rsp := connect.NewResponse(&testv1.Book{ Name: strings.Join([]string{msg.GetParent(), "books", msg.GetBookId()}, "/"), Parent: msg.GetParent(), CreateTime: timestamppb.New(time.Date(1968, 1, 1, 0, 0, 0, 0, time.UTC)), Title: book.GetTitle(), Author: book.GetAuthor(), Description: book.GetDescription(), Labels: book.GetLabels(), }) return rsp, nil }
Output: 200 OK application/json Arthur C. Clarke
Example (RpcClientToRestServer) ¶
package main import ( "context" "errors" "io" "log" "net/http" "net/http/httptest" "os" "regexp" "strconv" "strings" "time" "connectrpc.com/connect" "connectrpc.com/vanguard" testv1 "connectrpc.com/vanguard/internal/gen/vanguard/test/v1" "connectrpc.com/vanguard/internal/gen/vanguard/test/v1/testv1connect" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" ) func main() { // This example shows Vanguard adding RPC support to an REST server. This // lets organizations use RPC clients in new codebases without rewriting // existing REST services. logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */) // libraryREST is an http.Handler that implements a RESTful server. The // implementation doesn't use Protobuf or RPC directly. restHandler := &libraryREST{} // Using Vanguard, the server can also accept RPC traffic. The Vanguard // Transcoder handles both REST and RPC traffic, so there's no need to mount // the REST-only handler. services := []*vanguard.Service{vanguard.NewService( testv1connect.LibraryServiceName, restHandler, // This tells vanguard that the service implementation only supports REST. vanguard.WithTargetProtocols(vanguard.ProtocolREST), )} transcoder, err := vanguard.NewTranscoder(services) if err != nil { logger.Println(err) return } // We can serve RPC and REST traffic using any server that works with // http.Handlers. Since this is a testable example, we're using httptest. server := httptest.NewServer(transcoder) defer server.Close() // With the server running, we can make an RPC call using a generated client. client := testv1connect.NewLibraryServiceClient(server.Client(), server.URL) rsp, err := client.GetBook( context.Background(), connect.NewRequest(&testv1.GetBookRequest{ Name: "shelves/top/books/123", }), ) if err != nil { logger.Println(err) return } logger.Println(rsp.Msg.GetDescription()) } type libraryREST struct { libraryRPC } func (s *libraryREST) ServeHTTP(rsp http.ResponseWriter, req *http.Request) { urlPath := []byte(req.URL.Path) ctx := req.Context() var msg proto.Message var err error switch req.Method { case http.MethodGet: switch { case regexp.MustCompile("/v1/shelves/.*/books/.*").Match(urlPath): got, gotErr := s.GetBook(ctx, connect.NewRequest(&testv1.GetBookRequest{ Name: req.URL.Path[len("/v1/"):], })) msg, err = got.Msg, gotErr default: err = connect.NewError(connect.CodeNotFound, errors.New("method not found")) } case http.MethodPost: switch { case regexp.MustCompile("/v1/shelves/.*").Match(urlPath): var book testv1.Book body, _ := io.ReadAll(req.Body) _ = protojson.Unmarshal(body, &book) got, gotErr := s.CreateBook(ctx, connect.NewRequest(&testv1.CreateBookRequest{ Parent: req.URL.Path[len("/v1/"):], BookId: req.URL.Query().Get("book_id"), Book: &book, RequestId: req.URL.Query().Get("request_id"), })) msg, err = got.Msg, gotErr default: err = connect.NewError(connect.CodeNotFound, errors.New("method not found")) } default: err = connect.NewError(connect.CodeNotFound, errors.New("method not found")) } rsp.Header().Set("Content-Type", "application/json") var body []byte if err != nil { code := connect.CodeInternal if ce := (*connect.Error)(nil); errors.As(err, &ce) { code = ce.Code() } body = []byte(`{"code":` + strconv.Itoa(int(code)) + `, "message":"` + err.Error() + `"}`) } else { body, _ = protojson.Marshal(msg) } rsp.WriteHeader(http.StatusOK) _, _ = rsp.Write(body) } type libraryRPC struct { testv1connect.UnimplementedLibraryServiceHandler } func (s *libraryRPC) GetBook(_ context.Context, req *connect.Request[testv1.GetBookRequest]) (*connect.Response[testv1.Book], error) { msg := req.Msg rsp := connect.NewResponse(&testv1.Book{ Name: msg.GetName(), Parent: strings.Join(strings.Split(msg.GetName(), "/")[:2], "/"), CreateTime: timestamppb.New(time.Date(1968, 1, 1, 0, 0, 0, 0, time.UTC)), Title: "Do Androids Dream of Electric Sheep?", Author: "Philip K. Dick", Description: "Have you seen Blade Runner?", Labels: map[string]string{ "genre": "science fiction", }, }) return rsp, nil } func (s *libraryRPC) CreateBook(_ context.Context, req *connect.Request[testv1.CreateBookRequest]) (*connect.Response[testv1.Book], error) { msg := req.Msg book := req.Msg.GetBook() rsp := connect.NewResponse(&testv1.Book{ Name: strings.Join([]string{msg.GetParent(), "books", msg.GetBookId()}, "/"), Parent: msg.GetParent(), CreateTime: timestamppb.New(time.Date(1968, 1, 1, 0, 0, 0, 0, time.UTC)), Title: book.GetTitle(), Author: book.GetAuthor(), Description: book.GetDescription(), Labels: book.GetLabels(), }) return rsp, nil }
Output: Have you seen Blade Runner?
Index ¶
- Constants
- type Codec
- type JSONCodec
- func (j JSONCodec) IsBinary() bool
- func (j JSONCodec) MarshalAppend(base []byte, msg proto.Message) ([]byte, error)
- func (j JSONCodec) MarshalAppendField(base []byte, msg proto.Message, field protoreflect.FieldDescriptor) ([]byte, error)
- func (j JSONCodec) MarshalAppendStable(base []byte, msg proto.Message) ([]byte, error)
- func (j JSONCodec) Name() string
- func (j JSONCodec) Unmarshal(bytes []byte, msg proto.Message) error
- func (j JSONCodec) UnmarshalField(data []byte, msg proto.Message, field protoreflect.FieldDescriptor) error
- type ProtoCodec
- func (p *ProtoCodec) IsBinary() bool
- func (p *ProtoCodec) MarshalAppend(base []byte, msg proto.Message) ([]byte, error)
- func (p *ProtoCodec) MarshalAppendStable(base []byte, msg proto.Message) ([]byte, error)
- func (p *ProtoCodec) Name() string
- func (p *ProtoCodec) Unmarshal(bytes []byte, msg proto.Message) error
- type Protocol
- type RESTCodec
- type Service
- type ServiceOption
- func WithMaxGetURLBytes(limit uint32) ServiceOption
- func WithMaxMessageBufferBytes(limit uint32) ServiceOption
- func WithNoTargetCompression() ServiceOption
- func WithTargetCodecs(names ...string) ServiceOption
- func WithTargetCompression(names ...string) ServiceOption
- func WithTargetProtocols(protocols ...Protocol) ServiceOption
- func WithTypeResolver(resolver TypeResolver) ServiceOption
- type StableCodec
- type Transcoder
- type TranscoderOption
- func WithCodec(newCodec func(TypeResolver) Codec) TranscoderOption
- func WithCompression(name string, newCompressor func() connect.Compressor, ...) TranscoderOption
- func WithDefaultServiceOptions(serviceOptions ...ServiceOption) TranscoderOption
- func WithRules(rules ...*annotations.HttpRule) TranscoderOption
- func WithUnknownHandler(unknownHandler http.Handler) TranscoderOption
- type TypeResolver
Examples ¶
Constants ¶
const ( // ProtocolConnect indicates the Connect protocol. This protocol supports // unary and streaming endpoints. However, bidirectional streams are only // supported when combined with HTTP/2. ProtocolConnect = Protocol(iota + 1) // ProtocolGRPC indicates the gRPC protocol. This protocol can only be // used in combination with HTTP/2. It supports unary and all kinds of // streaming endpoints. ProtocolGRPC // ProtocolGRPCWeb indicates the gRPC-Web protocol. This is a tweak of the // gRPC protocol to support HTTP 1.1. This protocol supports unary and // streaming endpoints. However, bidirectional streams are only supported // when combined with HTTP/2. ProtocolGRPCWeb // ProtocolREST indicates the REST+JSON protocol. This protocol often // requires non-trivial transformations between HTTP requests and responses // and Protobuf request and response messages. // // Only methods that have the google.api.http annotation can be invoked // with this protocol. The annotation defines the "shape" of the HTTP // request and response, such as the URI path, HTTP method, and how URI // path components, query string parameters, and an optional request // body are mapped to the Protobuf request message. // // This protocol only supports unary and server-stream endpoints. ProtocolREST )
const ( // CompressionGzip is the name of the gzip compression algorithm. CompressionGzip = "gzip" // CompressionIdentity is the name of the "identity" compression algorithm, // which is the default and indicates no compression. CompressionIdentity = "identity" // CodecProto is the name of the protobuf codec. CodecProto = "proto" // CodecJSON is the name of the JSON codec. CodecJSON = "json" // DefaultMaxMessageBufferBytes is the default value for the maximum number // of bytes that can be buffered for a request or response payload. If a // payload exceeds this limit, the RPC will fail with a "resource exhausted" // error. DefaultMaxMessageBufferBytes = math.MaxUint32 // DefaultMaxGetURLBytes is the default value for the maximum number of bytes // that can be used for a URL with the Connect unary protocol using the GET // HTTP method. If a URL's length would exceed this limit, the POST HTTP method // will be used instead (and the request contents moved from the URL to the body). DefaultMaxGetURLBytes = 8 * 1024 )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Codec ¶
type Codec interface { // Name returns the name of this codec. This is used in content-type // strings to indicate this codec in the various RPC protocols. Name() string // MarshalAppend marshals the given message to bytes, appended to the // given base byte slice. The given slice may be empty, but its // capacity should be used when marshalling to bytes to reduce // additional allocations. MarshalAppend(base []byte, msg proto.Message) ([]byte, error) // Unmarshal unmarshals the given data into the given target message. Unmarshal(data []byte, msg proto.Message) error }
Codec is a message encoding format. It handles unmarshalling messages from bytes and back.
type JSONCodec ¶
type JSONCodec struct { MarshalOptions protojson.MarshalOptions UnmarshalOptions protojson.UnmarshalOptions }
JSONCodec implements Codec, StableCodec, and RESTCodec for the JSON format. It uses the protojson package for its implementation.
func NewJSONCodec ¶
func NewJSONCodec(res TypeResolver) *JSONCodec
NewJSONCodec is the default codec factory used for the codec named "json". The given resolver is used to unmarshal extensions and also to marshal and unmarshal instances of google.protobuf.Any.
By default, the returned codec is configured to emit unpopulated fields when marshalling and to discard unknown fields when unmarshalling.
func (JSONCodec) IsBinary ¶
IsBinary returns false, indicating that JSON is a text format. Implements StableCodec.
func (JSONCodec) MarshalAppend ¶
MarshalAppend implements Codec.
func (JSONCodec) MarshalAppendField ¶
func (j JSONCodec) MarshalAppendField(base []byte, msg proto.Message, field protoreflect.FieldDescriptor) ([]byte, error)
MarshalAppendField implements RESTCodec.
func (JSONCodec) MarshalAppendStable ¶
MarshalAppendStable implements StableCodec.
func (JSONCodec) UnmarshalField ¶
func (j JSONCodec) UnmarshalField(data []byte, msg proto.Message, field protoreflect.FieldDescriptor) error
UnmarshalField implements RESTCodec.
type ProtoCodec ¶
type ProtoCodec struct {
// contains filtered or unexported fields
}
ProtoCodec implements Codec and StableCodec for the binary Protobuf format. It uses the proto package for its implementation.
func NewProtoCodec ¶
func NewProtoCodec(res TypeResolver) *ProtoCodec
NewProtoCodec is the default codec factory used for the codec name "proto". The given resolver is used to unmarshal extensions.
func (*ProtoCodec) IsBinary ¶
func (p *ProtoCodec) IsBinary() bool
IsBinary returns true, indicating that Protobuf is a binary format. Implements StableCodec.
func (*ProtoCodec) MarshalAppend ¶
MarshalAppend implements Codec.
func (*ProtoCodec) MarshalAppendStable ¶
MarshalAppendStable implements StableCodec.
func (*ProtoCodec) Name ¶
func (p *ProtoCodec) Name() string
Name returns "proto". Implements Codec.
type RESTCodec ¶
type RESTCodec interface { Codec // MarshalAppendField marshals just the given field of the given message to // bytes, and appends it to the given base byte slice. MarshalAppendField(base []byte, msg proto.Message, field protoreflect.FieldDescriptor) ([]byte, error) // UnmarshalField unmarshals the given data into the given field of the given // message. UnmarshalField(data []byte, msg proto.Message, field protoreflect.FieldDescriptor) error }
RESTCodec is a Codec with additional methods for marshalling and unmarshalling individual fields of a message. This is necessary to support query string variables and request and response bodies whose value is a specific field, not an entire message. The extra methods are only used by the REST protocol.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service represents the configuration for a single RPC service.
func NewService ¶
func NewService(servicePath string, handler http.Handler, opts ...ServiceOption) *Service
NewService creates a new service definition for the given service path and handler. The service path must be the service's fully-qualified name, with an optional leading and trailing slash. This means you can provide generated constants for service names or you can provide the path returned by a New*Handler function generated by the [Protobuf plugin for Connect]. In fact, if you do not need to specify any service-specific options, you can directly wrap the call to the generated constructor with NewService:
vanguard.NewService(elizav1connect.NewElizaServiceHandler(elizaImpl))
If the given service path does not correspond to a known service (one whose schema is registered with the Protobuf runtime, usually from generated code), NewTranscoder will return an error. For these cases, where the corresponding service schema may be dynamically retrieved, use NewServiceWithSchema instead.
func NewServiceWithSchema ¶
func NewServiceWithSchema(schema protoreflect.ServiceDescriptor, handler http.Handler, opts ...ServiceOption) *Service
NewServiceWithSchema creates a new service using the given schema and handler. This option is appropriate for use with dynamic schemas.
The default type resolver for the service will use protoregistry.GlobalTypes if the given service matches a descriptor of the same name registered in protoregistry.GlobalFiles. Otherwise, the default resolver will use dynamic messages for the given service's request and response types. In either case, the default resolver will fall back to protoregistry.GlobalTypes for resolving extensions and message types for messages inside anypb.Any values.
type ServiceOption ¶
type ServiceOption interface {
// contains filtered or unexported methods
}
A ServiceOption configures how a Transcoder handles requests to a particular RPC service. ServiceOptions can be passed to NewService and NewServiceWithSchema. Default ServiceOptions, that apply to all services, can be defined by passing a WithDefaultServiceOptions option to NewTranscoder. This is useful when all or many services use the same options.
func WithMaxGetURLBytes ¶
func WithMaxGetURLBytes(limit uint32) ServiceOption
WithMaxGetURLBytes returns a service option that limits the size of URLs with the Connect unary protocol using the GET HTTP method. If a URL's length would exceed this limit, the POST HTTP method will be used instead (and the request contents moved from the URL to the body).
If set to zero or a negative value, a limit of 8 KB will be used.
func WithMaxMessageBufferBytes ¶
func WithMaxMessageBufferBytes(limit uint32) ServiceOption
WithMaxMessageBufferBytes returns a service option that limits buffering of data when handling the service to the given limit. If any payload in a request or response exceeds this, the RPC will fail with a "resource exhausted" error.
If set to zero or a negative value, a limit of 4 GB will be used.
func WithNoTargetCompression ¶
func WithNoTargetCompression() ServiceOption
WithNoTargetCompression returns a service option indicating that the server handler does not support compression.
func WithTargetCodecs ¶
func WithTargetCodecs(names ...string) ServiceOption
WithTargetCodecs returns a service option indicating that the service handler supports the given codecs. By default, the handler is assumed only to support the "proto" codec.
func WithTargetCompression ¶
func WithTargetCompression(names ...string) ServiceOption
WithTargetCompression returns a service option indicating that the service handler supports the given compression algorithms. By default, the handler is assumed only to support the "gzip" compression algorithm.
To configure the handler to not use any compression, one could use this option and supply no names. However, to make this scenario more readable, prefer WithNoTargetCompression instead.
func WithTargetProtocols ¶
func WithTargetProtocols(protocols ...Protocol) ServiceOption
WithTargetProtocols returns a service option indicating that the service handler supports the listed protocols. By default, the handler is assumed to support all but the REST protocol, which is true if the handler is a Connect handler (created using generated code from the protoc-gen-connect-go plugin or an explicit call to connect.NewUnaryHandler or its streaming equivalents).
func WithTypeResolver ¶
func WithTypeResolver(resolver TypeResolver) ServiceOption
WithTypeResolver returns a service option to use the given resolver when serializing and de-serializing messages. If not specified, this defaults to protoregistry.GlobalTypes.
type StableCodec ¶
type StableCodec interface { Codec // MarshalAppendStable is the same as MarshalAppend except that the // bytes produced must be deterministic and stable. Ideally, the // produced bytes represent a *canonical* encoding. But this is not // required as many codecs (including binary Protobuf and JSON) do // not have a well-defined canonical encoding format. MarshalAppendStable(b []byte, msg proto.Message) ([]byte, error) // IsBinary returns true for non-text formats. This is used to decide // whether the message query string parameter should be base64-encoded. IsBinary() bool }
StableCodec is an encoding format that can produce stable, deterministic output when marshalling data. This stable form is the result of the MarshalAppendStable method. So the codec's MarshalAppend method is free to produce unstable/non-deterministic output, if useful for improved performance. The performance penalty of stable output will only be taken when necessary.
This is used to encode messages that end up in the URL query string, for the Connect protocol when unary methods use the HTTP GET method. If the codec in use does not implement StableCodec then HTTP GET methods will not be used; a Transcoder will send all unary RPCs that use the Connect protocol and that codec as POST requests.
type Transcoder ¶
type Transcoder struct {
// contains filtered or unexported fields
}
Transcoder is a Vanguard handler which acts like a router and a middleware. It transforms all supported input protocols (Connect, gRPC, gRPC-Web, REST) into a protocol that the service handlers support. It can do simple routing based on RPC method name, for simple protocols like Connect, gRPC, and gRPC-Web; but it can also route based on REST-ful URI paths configured with HTTP transcoding annotations.
See the package-level examples for sample usage.
func NewTranscoder ¶
func NewTranscoder(services []*Service, opts ...TranscoderOption) (*Transcoder, error)
NewTranscoder creates a new transcoder that handles the given services, with the configuration described by the given options. A non-nil error is returned if there is an issue with this configuration.
The returned handler does the routing and dispatch to the RPC handlers associated with each provided service. Routing supports more than just the service path provided to NewService since HTTP transcoding annotations are used to also support REST-ful URI paths for each method.
The returned handler also acts like a middleware, transparently "upgrading" the RPC handlers to support incoming request protocols they wouldn't otherwise support. This can be used to upgrade Connect handlers to support REST requests (based on HTTP transcoding configuration) or gRPC handlers to support Connect, gRPC-Web, or REST. This can even be used with a reverse proxy handler, to translate all incoming requests to a single protocol that another backend server supports.
If any options given implement ServiceOption, they are treated as default service options and apply to all configured services, unless overridden by a particular service.
func (*Transcoder) ServeHTTP ¶
func (t *Transcoder) ServeHTTP(writer http.ResponseWriter, request *http.Request)
ServeHTTP implements http.Handler, dispatching requests for configured services and transcoding protocols and message encoding as needed.
type TranscoderOption ¶
type TranscoderOption interface {
// contains filtered or unexported methods
}
TranscoderOption is an option used to configure a Transcoder. See NewTranscoder.
func WithCodec ¶
func WithCodec(newCodec func(TypeResolver) Codec) TranscoderOption
WithCodec returns an option that instructs the transcoder to use the given function for instantiating codec implementations. The function is immediately invoked in order to determine the name of the codec. The name reported by codecs created with the function should all return the same name. (Otherwise, behavior is undefined.)
By default, "proto" and "json" codecs are supported using default options. This option can be used to support additional codecs or to override the default implementations (such as to change serialization or de-serialization options).
func WithCompression ¶
func WithCompression(name string, newCompressor func() connect.Compressor, newDecompressor func() connect.Decompressor) TranscoderOption
WithCompression returns an option that instructs the transcoder to use the given functions to instantiate compressors and decompressors for the given compression algorithm name.
By default, "gzip" compression is supported using default options. This option can be used to support additional compression algorithms or to override the default "gzip" implementation (such as to change the compression level).
func WithDefaultServiceOptions ¶
func WithDefaultServiceOptions(serviceOptions ...ServiceOption) TranscoderOption
WithDefaultServiceOptions returns an option that configures the given service options as defaults. They will apply to all services passed to NewTranscoder, except where overridden via an explicit ServiceOption passed to NewService / NewServiceWithSchema.
Providing multiple instances of this option will be cumulative: the union of all defaults are used with later options overriding any previous options.
func WithRules ¶
func WithRules(rules ...*annotations.HttpRule) TranscoderOption
WithRules returns an option that adds HTTP transcoding configuration to the set of configured services. The given rules must have a selector defined, and the selector must match at least one configured method. Otherwise, NewTranscoder will report a configuration error.
func WithUnknownHandler ¶
func WithUnknownHandler(unknownHandler http.Handler) TranscoderOption
WithUnknownHandler returns an option that instructs the transcoder to delegate to the given handler when a request arrives for an unknown endpoint. If no such option is used, the transcoder will reply with a simple "404 Not Found" error.
type TypeResolver ¶
type TypeResolver interface { protoregistry.MessageTypeResolver protoregistry.ExtensionTypeResolver }
TypeResolver can resolve message and extension types and is used to instantiate messages as needed for the middleware to serialize/de-serialize request and response payloads.
Implementations of this interface should be comparable, so they can be used as map keys. Typical implementations are pointers to structs, which are suitable.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
internal
|
|
examples/pets/internal/gen/io/swagger/petstore/v2/petstorev2connect
The service defined herein comes from v2 of the Petstore service, which is used as an example for Swagger/OpenAPI.
|
The service defined herein comes from v2 of the Petstore service, which is used as an example for Swagger/OpenAPI. |
gen/io/swagger/petstore/v2/petstorev2connect
The service defined herein comes from v2 of the Petstore service, which is used as an example for Swagger/OpenAPI.
|
The service defined herein comes from v2 of the Petstore service, which is used as an example for Swagger/OpenAPI. |
Package vanguardgrpc provides convenience functions to make it easy to wrap your [grpc.Server] with a [vanguard.Transcoder], to upgrade it to supporting Connect, gRPC-Web, and REST+JSON protocols.
|
Package vanguardgrpc provides convenience functions to make it easy to wrap your [grpc.Server] with a [vanguard.Transcoder], to upgrade it to supporting Connect, gRPC-Web, and REST+JSON protocols. |