-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How can I use dynamic schemas? #104
Comments
Hey @anhnmt thanks for trying out the library! For dynamic protobuf files you can create the service with To clarify is it a gRPC server on localhost:8080? To create a reverse proxy you could setup the proxy server as: var schema protoreflect.ServiceDescriptor // Loaded dynamically
remote, _ := url.Parse("http://localhost:8080")
proxy := httputil.NewSingleHostReverseProxy(remote)
transcoder := vanguard.NewTranscoder(
[]*vanguard.Service{
vanguard.NewServiceWithSchema(schema, proxy),
},
) |
@anhnmt, hi! Glad you are finding this repo valuable! For a little more info on obtaining descriptors, to use with
|
@emcfarlane I use httputil.NewSingleHostReverseProxy but it seems it only reverses HTTP proxies, gRPC does not. |
@anhnmt, gRPC uses HTTP under the hood. If you are having an issue, it is likely due to use of HTTP 1.1, whereas gRPC requires HTTP/2. If you are not using TLS (where the HTTP/2 protocol can be negotiated during the TLS handshake), then you need to be using "HTTP/2 over clear text", also called "H2C". There is more detail in the Connect docs, since this is also necessary to use the gRPC protocol with the connect-go module: https://connectrpc.com/docs/go/deployment/#h2c In particular, you'd need to wrap your reverse proxy handler using |
@jhump, I used h2c but it seems I made a mistake in some step so I still can't connect to gRPC |
Hey @anhnmt, I think the reverse proxy should be created with a http2 transport here: proxy := httputil.NewSingleHostReverseProxy(target)
proxy.Transport = &http2.Transport{AllowHTTP: true}
h2cHandler := h2c.NewHandler(proxy, &http2.Server{}) Let me know if this works for you. You may need to configure the transport for your server configuration. |
proxy.Transport = &http2.Transport{AllowHTTP: true} I also tried your method but encountered some other problems, for example:
|
proxy := httputil.NewSingleHostReverseProxy(target)
+ proxy.Transport = &http2.Transport{
+ AllowHTTP: true,
+ DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) {
+ // If you're also using this client for non-h2c traffic, you may want
+ // to delegate to tls.Dial if the network isn't TCP or the addr isn't
+ // in an allowlist.
+ return net.Dial(network, addr)
+ },
+ }
h2cHandler := h2c.NewHandler(proxy, &http2.Server{}) Tested with |
@emcfarlane vanguard-go/internal/examples/pets/cmd/pets-fe/main.go Lines 66 to 71 in d7faf70
Also, can you give me some feedback on optimizing this part? import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httputil"
"net/url"
"os"
"path/filepath"
"time"
"connectrpc.com/vanguard"
"github.com/jhump/protoreflect/desc/protoparse"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/dynamicpb"
)
googleapis := []string{
"google/api/annotations.proto",
"google/api/http.proto",
"google/protobuf/descriptor.proto",
}
files := append(googleapis, "user/v1/user.proto")
p := protoparse.Parser{
ImportPaths: []string{
"proto",
"googleapis",
},
Accessor: func(filename string) (io.ReadCloser, error) {
return ReadFileContent(filename)
},
}
fds, err := p.ParseFiles(files...)
if err != nil {
log.Err(err).Msg("could not parse given files")
return
}
fileDescriptors := make([]*descriptorpb.FileDescriptorProto, 0)
for _, fd := range fds {
fileDescriptors = append(fileDescriptors, fd.AsFileDescriptorProto())
}
newFiles, err := protodesc.NewFiles(&descriptorpb.FileDescriptorSet{
File: fileDescriptors,
})
if err != nil {
log.Err(err).Msg("could not parse given files")
return
}
types := dynamicpb.NewTypes(newFiles)
name, err := newFiles.FindDescriptorByName("user.v1.UserService")
if err != nil {
return
}
serviceDesc := name.ParentFile().Services().ByName("UserService") |
The use of A bug I noticed in the proto. The option in
Should be
{"code":3,"message":"invalid parameter \"page\" invalid character '/' after top-level value","details":[]}
{"code":2, "message":"response uses incorrect codec: expecting \"json\" but instead got \"?\"", "details":[]} |
I saw the use of In the existing code, which does convert descriptors and construct a registry (using resolver := &protoregistry.Files{}
for _, fileDesc := range parsedFiles {
if err := resolver.RegisterFile(fileDesc.UnwrapFile()); err != nil {
return err
}
} (Having said that, using As @emcfarlane said, you could use an image or file descriptor set file, which may be simpler to distribute to production containers than all of the source needed to compile the schema. And if you push the code to the BSR, then you could instead download the schema via a reflection endpoint. In fact, there's a Go library that includes the ability to watch a schema in the BSR, downloading a new version when one becomes available (and, under the hood, it uses that reflection endpoint). |
@jhump, I used My source code: https://github.com/anhnmt/gprc-dynamic-proto/blob/fc77aa12da23fbaaa171e97b4814c8185ba5ab05/cmd/protocompile/main.go
|
@anhnmt, ah, right. Sorry, I forgot about the HTTP annotations. It is indeed expected that they are dynamic extensions from the compiler (since the compiler's version of the message definition could differ from the version linked into the calling program). Seems like a good addition to protocompile would be a helper to address that, or maybe even a compiler option so that you don't have to do anything as a post-process. The helper or option would basically do the same thing that protoparse does, which is to re-parse custom options using |
I have a proto file and gprc client address localhost:8080
How can I connect to gprc client using the above proto file without having to generate .pb.go or .connect.go files?
This mechanism of action may look like this: https://docs.konghq.com/hub/kong-inc/grpc-gateway/how-to/
Also I quite enjoy using this library, thank you for creating this wonderful library 😁
The text was updated successfully, but these errors were encountered: