gRPC and grpc-gateway
Two separate Go modules wrap gRPC servers and grpc-gateway REST frontends as shost services:
go get github.com/dvislobokov/shost/grpcsvc # gRPC server
go get github.com/dvislobokov/shost/grpcgw # grpc-gateway (REST → gRPC transcoding)They live outside the core module so that shost itself stays dependency-free; both require Go 1.25 or newer.
gRPC server (grpcsvc)
grpcsvc.New runs a *grpc.Server with the full shost lifecycle: readiness once the listener accepts, graceful stop under the host's shutdown deadline, forceful stop when the deadline expires.
srv := grpc.NewServer()
pb.RegisterGreeterServer(srv, &greeter{})
host := shost.New().
AddService(grpcsvc.New(":9090", srv)).
MustBuild()func New(addr string, srv *grpc.Server, opts ...Option) *Service // panics on nil server
func WithName(name string) Option // default "grpc <addr>"
func (s *Service) Name() string
func (s *Service) Ready() <-chan struct{} // closes once the listener accepts
func (s *Service) Addr() string // actual address (useful with ":0"); "" before ready
func (s *Service) Start(ctx context.Context) error
func (s *Service) Stop(ctx context.Context) errorRegister your gRPC services on srv before passing it in. Stop runs GracefulStop bounded by the shared shutdown deadline; if in-flight RPCs don't drain in time, the server is stopped forcefully and Stop returns a "graceful shutdown timed out" error wrapping ctx.Err(). grpc.ErrServerStopped is treated as a clean exit.
grpc-gateway (grpcgw)
grpcgw runs a grpc-gateway HTTP server — REST→gRPC transcoding — as a shost service, owning the boilerplate: runtime.ServeMux construction, the client connection to the gRPC endpoint, handler registration, and the HTTP server lifecycle.
gw := grpcgw.New(":8081", "localhost:9090",
grpcgw.Register(pb.RegisterGreeterHandler),
grpcgw.Register(pb.RegisterOrdersHandler),
)
host := shost.New().
AddService(grpcsvc.New(":9090", grpcServer)).
AddService(gw). // starts after the gRPC server is ready
MustBuild()type RegisterFunc func(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error
func New(addr, endpoint string, opts ...Option) *Service // panics without at least one Register
func Register(fn RegisterFunc) Option // protoc-generated RegisterXxxHandler; at least one required
func WithName(name string) Option // default "grpc-gateway <addr>"
func WithServeMuxOptions(opts ...runtime.ServeMuxOption) Option
func WithDialOptions(opts ...grpc.DialOption) Option // replaces the default insecure credentials
func WithServer(configure func(*http.Server)) Option // timeouts, TLS, ...
func WithHandler(wrap func(http.Handler) http.Handler) Option // middleware: logging, CORS, auth
func (s *Service) Name() string
func (s *Service) Ready() <-chan struct{}
func (s *Service) Addr() string
func (s *Service) Start(ctx context.Context) error
func (s *Service) Stop(ctx context.Context) errorDetails worth knowing:
- The connection to
endpointis plaintext by default — the usual same-host gateway setup.WithDialOptionsreplaces the defaults, so supply your own transport credentials when the gRPC server is remote or TLS-terminated. Readycloses after allRegisterfunctions have run and the listener accepts, so ordering the gateway after the gRPC server in the builder gives a fully wired pipeline before the host reports started.Stopuseshttp.Server.Shutdownunder the shared deadline, then forcefulClosewith a wrapped error if the deadline expires — same contract as httpsvc.