Skip to content

Commit

Permalink
Use options for binding services
Browse files Browse the repository at this point in the history
  • Loading branch information
emcfarlane committed Oct 12, 2023
1 parent 0898bae commit ed7bc03
Show file tree
Hide file tree
Showing 15 changed files with 239 additions and 204 deletions.
5 changes: 4 additions & 1 deletion internal/examples/connect+grpc/cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"buf.build/gen/go/connectrpc/eliza/grpc/go/connectrpc/eliza/v1/elizav1grpc"
elizav1 "buf.build/gen/go/connectrpc/eliza/protocolbuffers/go/connectrpc/eliza/v1"
"connectrpc.com/vanguard"
"connectrpc.com/vanguard/vanguardgrpc"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
Expand All @@ -42,7 +43,9 @@ func main() {
// Now wrap it with a Vanguard transcoder to upgrade it to
// also supporting Connect and gRPC-Web (and even REST,
// if the gRPC service schemas have HTTP annotations).
handler, err := vanguardgrpc.NewTranscoder(server)
handler, err := vanguard.NewTranscoder(
vanguardgrpc.WithGRPCServer(server),
)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
Expand Down
5 changes: 3 additions & 2 deletions internal/examples/fileserver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ func main() {
FS: os.DirFS(*directory),
}
// And wrap it with Vanguard.
service := vanguard.NewService(testv1connect.NewContentServiceHandler(serviceHandler))
handler, err := vanguard.NewTranscoder([]*vanguard.Service{service})
handler, err := vanguard.NewTranscoder(
vanguard.WithService(testv1connect.NewContentServiceHandler(serviceHandler)),
)
if err != nil {
log.Fatal(err)
}
Expand Down
6 changes: 4 additions & 2 deletions internal/examples/pets/cmd/pets-be/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ func main() {
// Wrap the proxy handler with Vanguard, so it can accept Connect, gRPC, or gRPC-Web
// and transform the requests to REST+JSON.
handler, err := vanguard.NewTranscoder(
[]*vanguard.Service{vanguard.NewService(petstorev2connect.PetServiceName, proxy)},
vanguard.WithTargetProtocols(vanguard.ProtocolREST),
vanguard.WithService(petstorev2connect.PetServiceName, proxy),
vanguard.WithDefaultServiceOptions(
vanguard.WithTargetProtocols(vanguard.ProtocolREST),
),
)
if err != nil {
log.Fatal(err)
Expand Down
2 changes: 1 addition & 1 deletion internal/examples/pets/cmd/pets-fe/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func main() {
// transform it to a particular protocol (based on the port used to send the request)
// before sending to the pets-be server.
handler, err := vanguard.NewTranscoder(
[]*vanguard.Service{vanguard.NewService(petstorev2connect.PetServiceName, proxy, opts...)},
vanguard.WithService(petstorev2connect.PetServiceName, proxy, opts...),
)
if err != nil {
log.Fatal(err)
Expand Down
10 changes: 5 additions & 5 deletions transcoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ import (
"google.golang.org/protobuf/proto"
)

// 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.
// Transcoder implements protocol conversion to and from all supported protocols,
// encoding formats, and compression schemes. It can do simple routing based on
// RPC method name, for simple protocols like Connect, gRPC, and gRPC-Web. It
// also will route based on REST-ful URI paths configured with HTTP transcoding
// annotations.
type Transcoder struct {
bufferPool bufferPool
codecs codecMap
Expand Down
64 changes: 38 additions & 26 deletions transcoder_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func BenchmarkServeHTTP(b *testing.B) {
rspGRPCBody := envelopePayload(1, rspMsgProtoComp)

handler, err := NewTranscoder(
[]*Service{NewService(
WithService(
testv1connect.LibraryServiceName,
benchHandler(b, rspGRPCBody, http.Header{
"Grpc-Encoding": []string{"gzip"},
Expand All @@ -136,8 +136,10 @@ func BenchmarkServeHTTP(b *testing.B) {
}, http.Header{
"Grpc-Status": []string{"0"},
}),
)},
WithTargetProtocols(ProtocolGRPC),
),
WithDefaultServiceOptions(
WithTargetProtocols(ProtocolGRPC),
),
)
require.NoError(b, err)

Expand Down Expand Up @@ -170,18 +172,20 @@ func BenchmarkServeHTTP(b *testing.B) {
rspGRPCBody := envelopePayload(0, rspMsgProto)

handler, err := NewTranscoder(
[]*Service{NewService(
WithService(
testv1connect.LibraryServiceName,
benchHandler(b, rspGRPCBody, http.Header{
"Content-Type": []string{"application/grpc+proto"},
"Trailer": []string{"Grpc-Status, Grpc-Message"},
}, http.Header{
"Grpc-Status": []string{"0"},
}),
)},
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
WithNoTargetCompression(),
),
WithDefaultServiceOptions(
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
WithNoTargetCompression(),
),
)
require.NoError(b, err)

Expand Down Expand Up @@ -217,15 +221,17 @@ func BenchmarkServeHTTP(b *testing.B) {
rspGRPCBody := envelopePayload(0, rspMsgProto)

handler, err := NewTranscoder(
[]*Service{NewService(
WithService(
testv1connect.LibraryServiceName,
benchHandler(b, rspMsgJSON, http.Header{
"Content-Type": []string{"application/json"},
}, nil),
)},
WithTargetProtocols(ProtocolREST),
WithTargetCodecs(CodecJSON),
WithNoTargetCompression(),
),
WithDefaultServiceOptions(
WithTargetProtocols(ProtocolREST),
WithTargetCodecs(CodecJSON),
WithNoTargetCompression(),
),
)
require.NoError(b, err)

Expand Down Expand Up @@ -258,18 +264,20 @@ func BenchmarkServeHTTP(b *testing.B) {
rspGRPCBody := envelopePayload(0, rspMsgProto)

handler, err := NewTranscoder(
[]*Service{NewService(
WithService(
testv1connect.LibraryServiceName,
benchHandler(b, rspGRPCBody, http.Header{
"Content-Type": []string{"application/grpc+proto"},
"Trailer": []string{"Grpc-Status, Grpc-Message"},
}, http.Header{
"Grpc-Status": []string{"0"},
}),
)},
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
WithNoTargetCompression(),
),
WithDefaultServiceOptions(
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
WithNoTargetCompression(),
),
)
require.NoError(b, err)

Expand Down Expand Up @@ -303,7 +311,7 @@ func BenchmarkServeHTTP(b *testing.B) {
rspGRPCBody := envelopePayload(1, rspMsgProtoComp)

handler, err := NewTranscoder(
[]*Service{NewService(
WithService(
testv1connect.LibraryServiceName,
benchHandler(b, rspGRPCBody, http.Header{
"Content-Type": []string{"application/grpc+proto"},
Expand All @@ -312,9 +320,11 @@ func BenchmarkServeHTTP(b *testing.B) {
}, http.Header{
"Grpc-Status": []string{"0"},
}),
)},
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
),
WithDefaultServiceOptions(
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
),
)
require.NoError(b, err)

Expand Down Expand Up @@ -351,7 +361,7 @@ func BenchmarkServeHTTP(b *testing.B) {
rspGRPC := envelopePayload(0, marshalProto(&emptypb.Empty{}))

handler, err := NewTranscoder(
[]*Service{NewService(
WithService(
testv1connect.ContentServiceName,
benchHandler(b, rspGRPC, http.Header{
"Content-Type": []string{"application/grpc+proto"},
Expand All @@ -360,9 +370,11 @@ func BenchmarkServeHTTP(b *testing.B) {
}, http.Header{
"Grpc-Status": []string{"0"},
}),
)},
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
),
WithDefaultServiceOptions(
WithTargetProtocols(ProtocolGRPC),
WithTargetCodecs(CodecProto),
),
)
require.NoError(b, err)

Expand Down
62 changes: 33 additions & 29 deletions transcoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestTranscoder_BufferTooLargeFails(t *testing.T) {
}{
{
name: "enveloping_reader",
expectation: func(t *testing.T, rw http.ResponseWriter, req *http.Request) {
expectation: func(t *testing.T, _ http.ResponseWriter, req *http.Request) {
t.Helper()
_, ok := req.Body.(*envelopingReader)
assert.True(t, ok, "request body should be *envelopingReader")
Expand All @@ -114,7 +114,7 @@ func TestTranscoder_BufferTooLargeFails(t *testing.T) {
},
{
name: "enveloping_writer",
expectation: func(t *testing.T, rsp http.ResponseWriter, req *http.Request) {
expectation: func(t *testing.T, rsp http.ResponseWriter, _ *http.Request) {
t.Helper()
rw, ok := rsp.(*responseWriter)
require.True(t, ok, "response writer should be *responseWriter")
Expand Down Expand Up @@ -466,26 +466,28 @@ func TestTranscoder_BufferTooLargeFails(t *testing.T) {
muxTestModes := []struct {
name string
optsOnService bool
makeMux func(*testRequest, []*Service) (http.Handler, error)
makeMux func(*testRequest, ...TranscoderOption) (http.Handler, error)
}{
{
name: "default_svc_opts",
optsOnService: false,
makeMux: func(req *testRequest, svcs []*Service) (http.Handler, error) {
opts := make([]TranscoderOption, 0, len(req.svcOpts)+2)
for _, svcOpt := range req.svcOpts {
opts = append(opts, svcOpt)
}
opts = append(opts, WithMaxMessageBufferBytes(1024))
return NewTranscoder(svcs, opts...)
makeMux: func(req *testRequest, opts ...TranscoderOption) (http.Handler, error) {
svcOpts := append([]ServiceOption{
WithMaxMessageBufferBytes(1024),
}, req.svcOpts...)
opts = append(opts, WithDefaultServiceOptions(svcOpts...))
return NewTranscoder(opts...)
},
},
{
name: "per_svc_options",
optsOnService: true,
makeMux: func(req *testRequest, svcs []*Service) (http.Handler, error) {
makeMux: func(_ *testRequest, opts ...TranscoderOption) (http.Handler, error) {
// svcs already have options defined on them
return NewTranscoder(svcs, WithMaxMessageBufferBytes(1024))
opts = append(opts, WithDefaultServiceOptions(
WithMaxMessageBufferBytes(1024),
))
return NewTranscoder(opts...)
},
},
}
Expand Down Expand Up @@ -514,10 +516,10 @@ func TestTranscoder_BufferTooLargeFails(t *testing.T) {
if mode.optsOnService {
svcOpts = testReq.svcOpts
}
handler, err := mode.makeMux(testReq, []*Service{
NewService(testv1connect.LibraryServiceName, rpcHandler, svcOpts...),
NewService(testv1connect.ContentServiceName, rpcHandler, svcOpts...),
})
handler, err := mode.makeMux(testReq,
WithService(testv1connect.LibraryServiceName, rpcHandler, svcOpts...),
WithService(testv1connect.ContentServiceName, rpcHandler, svcOpts...),
)
require.NoError(t, err)
server := httptest.NewUnstartedServer(handler)
server.EnableHTTP2 = true
Expand Down Expand Up @@ -564,22 +566,24 @@ func TestTranscoder_ConnectGetUsesPostIfRequestTooLarge(t *testing.T) {
)

handlerWithDefaultSvcOpt, err := NewTranscoder(
[]*Service{NewService(testv1connect.LibraryServiceName, svcHandler)},
WithMaxGetURLBytes(512),
WithNoTargetCompression(),
WithService(testv1connect.LibraryServiceName, svcHandler),
WithDefaultServiceOptions(
WithMaxGetURLBytes(512),
WithNoTargetCompression(),
),
)
require.NoError(t, err)
serverWithDefaultSvcOpt := httptest.NewServer(handlerWithDefaultSvcOpt)
disableCompression(serverWithDefaultSvcOpt)
t.Cleanup(serverWithDefaultSvcOpt.Close)

handlerWithPerSvcOpt, err := NewTranscoder([]*Service{
NewService(
handlerWithPerSvcOpt, err := NewTranscoder(
WithService(
testv1connect.LibraryServiceName, svcHandler,
WithMaxGetURLBytes(512),
WithNoTargetCompression(),
),
})
)
require.NoError(t, err)
serverWithPerSvcOpt := httptest.NewServer(handlerWithPerSvcOpt)
disableCompression(serverWithPerSvcOpt)
Expand Down Expand Up @@ -658,17 +662,17 @@ func TestTranscoder_Errors(t *testing.T) {
rpcHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
http.Error(w, "nope", http.StatusTeapot)
})
services := []*Service{
NewService(testv1connect.LibraryServiceName, rpcHandler),
NewService(testv1connect.ContentServiceName, rpcHandler),
opts := []TranscoderOption{
WithService(testv1connect.LibraryServiceName, rpcHandler),
WithService(testv1connect.ContentServiceName, rpcHandler),
}
handler, err := NewTranscoder(services)
handler, err := NewTranscoder(opts...)
require.NoError(t, err)
unknownHandler, err := NewTranscoder(services, WithUnknownHandler(
unknownHandler, err := NewTranscoder(append(opts, WithUnknownHandler(
http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
writer.WriteHeader(http.StatusFailedDependency)
}),
))
))...)
require.NoError(t, err)

testCases := []struct {
Expand Down Expand Up @@ -1055,7 +1059,7 @@ func TestTranscoder_PassThrough(t *testing.T) {
testv1connect.UnimplementedContentServiceHandler{},
connect.WithInterceptors(&interceptor),
)
handler, err := NewTranscoder([]*Service{NewService(contentPath, checkPassThrough(contentHandler))})
handler, err := NewTranscoder(WithService(contentPath, checkPassThrough(contentHandler)))
require.NoError(t, err)

// Use HTTP/2 so we can test a bidi stream.
Expand Down
Loading

0 comments on commit ed7bc03

Please sign in to comment.