contrib
contrib copied to clipboard
entproto: make it possible to configure generated output so that it can work with Buf/Connect
Hi Team,
This PR adds some extra configuration to the generate Hook so that it can output generated code that works with BufBuild's Connect.
Specific changes:
- Make all method names unique so that specific keys don't collide or generate the method
delete()in JS, and follow the naming conventions specified by the linter. - Don't create the
generate.gofile since we're usingbuf generateinstead of protoc. - Allow configuring the generation target so we can collocate generated
.protowith other hand written files outside of./ent
Hey @ivanvanderbyl
Thanks for working on this. I prefer to review / discuss each option in its own PR. This allows for more granular discussion on each change as it doesn't bundle them together.
In addition, please add tests 🙏
Hi @rotemtam — okay, I will find some time this week to break it apart.
I love to see this. I'm working with Connect as well. It requires a bit of boilerplate, but I'm just wrapping ent proto's service implementation inside of Connect methods. For example, my handlers look like this:
package handlers
import (
"context"
"github.com/bufbuild/connect-go"
"github.com/pgdevelopers/xxxx/ent/generated"
entpbv1 "github.com/pgdevelopers/xxxx/ent/proto/entpb"
xxxxv1connect "github.com/xxxx/ent/proto/entpb/entpbconnect"
"google.golang.org/protobuf/types/known/emptypb"
)
type DeviceStateServer struct{}
var deviceStateSvc *entpbv1.DeviceStateService
// NewDeviceStateServer returns a new DeviceStateServer.
func NewDeviceStateServer(client *generated.Client) xxxxv1connect.DeviceStateServiceHandler {
deviceStateSvc = entpbv1.NewDeviceStateService(client)
return &DeviceStateServer{}
}
func (s *DeviceStateServer) Get(ctx context.Context, c *connect.Request[entpbv1.GetDeviceStateRequest]) (*connect.Response[entpbv1.DeviceState], error) {
resp, err := deviceStateSvc.Get(ctx, c.Msg)
if err != nil {
return nil, err
}
return connect.NewResponse(resp), nil
}
And I register them like this:
...
func setupHandlers(client *generated.Client) *http.ServeMux {
mux := http.NewServeMux()
mux.Handle(xxxxv1connect.NewDeviceStateServiceHandler(
handlers.NewDeviceStateServer(client),
connect.WithInterceptors(
otelconnect.NewInterceptor(),
interceptors.NewAuthInterceptor(tokenHeader, authToken),
),
))
return mux
}
func setupServer(mux *http.ServeMux) *http.Server {
srv := &http.Server{
Addr: ":" + port,
Handler: h2c.NewHandler(
mux,
&http2.Server{},
),
ReadHeaderTimeout: time.Second,
ReadTimeout: 5 * time.Minute,
WriteTimeout: 5 * time.Minute,
MaxHeaderBytes: 8 * 1024, // 8KiB
}
return srv
}
func main() {
srv := setupServer(setupHandlers(devicesClient))
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("HTTP listen and serve: %v", err)
}
}
I'd love to talk more about this at some point!