go-masonry/mortar

[feature] Provide a way to custom runtime.ServerMux

liemlhdbeatvn opened this issue · 3 comments

Context: I need a way to add CORS support.

Problem: Currently, there's no way to inject custom runtime.ServerMux and set it using RestBuilder.

Solution: Add support to inject custom runtime.ServerMux at

type httpServerDeps struct {

Hi @liemlhdbeatvn, it is actually possible to specify your custom *runtime.ServerMux.
Here is how to inject a custom *runtime.ServerMux

You probably use this HTTPServerBuilderFxOption option in your service, usually found in /app/mortar/http.go file (if you using a provided template).

func HttpServerFxOptions() fx.Option {
	return fx.Options(
		providers.HTTPServerBuilderFxOption(),               // Web Server Builder
...

You will need to replace it with a different one that also returns GRPCWebServiceBuilder type.
Since this constructor github.com/go-masonry/mortar/constructors/service.go#L23 expect it.

Here you can find an example of how it's currently build github.com/go-masonry/mortar/constructors/partial/httpserver.go

// HTTPServerBuilder true to it's name, it is partially initialized builder.
//
// It uses some default assumptions and configurations, which are mostly good.
// However, if you need to customize your configuration it's better to build yours from scratch
//
func HTTPServerBuilder(deps httpServerDeps) serverInt.GRPCWebServiceBuilder {
	builder := server.Builder().SetPanicHandler(deps.panicHandler).SetLogger(deps.Logger.Debug)
	host := deps.Config.Get(confkeys.Host).String()
	// GRPC port
	if grpcPort := deps.Config.Get(confkeys.ExternalGRPCPort); grpcPort.IsSet() {
		builder = builder.ListenOn(fmt.Sprintf("%s:%d", host, grpcPort.Int()))
	}
	// GRPC server interceptors
	if len(deps.UnaryInterceptors) > 0 {
		interceptorsOption := grpc.ChainUnaryInterceptor(deps.UnaryInterceptors...)
		builder = builder.AddGRPCServerOptions(interceptorsOption)
	}
	builder = deps.buildExternalAPI(builder)
	return deps.buildInternalAPI(builder)
}

There are 2 Webservices you can customize: External and Internal.
This AddRESTServerConfiguration() RESTBuilder method found in GRPCWebServiceBuilder interface returns a special REST Server RESTBuilder interface and that one have this SetCustomGRPCGatewayMux(mux *runtime.ServeMux) RESTBuilder option

Hmm, end up using custom *http.Server. It's worked now.

@liemlhdbeatvn we added a new feature that might solve what you need in v1.0.26.
9d0b364
There are 2 new fx groups called externalHttpInterceptors and internalHttpInterceptors
Here is an example:

func InternalRootHandlersFxOption() fx.Option {
	return fx.Provide(
		fx.Annotated{
			Group: groups.InternalHTTPInterceptors + ",flatten",
			Target: func() []serverInt.GRPCGatewayInterceptor {
				return []serverInt.GRPCGatewayInterceptor{
					func(handler http.Handler) http.Handler {
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
							// check CORS here
                                                        // or intercept the root handler by checking r.URL.Path == "/"

							handler.ServeHTTP(w, r)
						})
					},
				}
			},
		})
}