func WithGatewayOptions(opt ...runtime.ServeMuxOption) Option {
	return func(g *gateway) {
		g.gatewayMuxOptions = append(g.gatewayMuxOptions, opt...)
	}
}
WithGatewayOptions allows for additional gateway ServeMuxOptions beyond the
default ProtoMessageErrorHandler and MetadataAnnotator from this package
package gateway
import (
	"context"
	"net/http"
	"net/url"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"github.com/infobloxopen/atlas-app-toolkit/query"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)
const (
	DefaultServerAddress = ":9090"
)
type Option func(*gateway)
type registerFunc func(context.Context, *runtime.ServeMux, string, []grpc.DialOption) (err error)
type gateway struct {
	serverAddress     string
	serverDialOptions []grpc.DialOption
	endpoints         map[string][]registerFunc
	mux               *http.ServeMux
	gatewayMuxOptions []runtime.ServeMuxOption
}
func ClientUnaryInterceptor(parentCtx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
	raw, ok := Header(parentCtx, query_url)
	if ok {
		request, err := url.Parse(raw)
		if err != nil {
			return status.Error(codes.InvalidArgument, err.Error())
		}
		vals := request.Query()
		if v := vals.Get(sortQueryKey); v != "" {
			s, err := query.ParseSorting(v)
			if err != nil {
				return status.Error(codes.InvalidArgument, err.Error())
			}
			err = SetCollectionOps(req, s)
			if err != nil {
				return err
			}
		}
		if v := vals.Get(fieldsQueryKey); v != "" {
			fs := query.ParseFieldSelection(v)
			err := SetCollectionOps(req, fs)
			if err != nil {
				return err
			}
		}
		if v := vals.Get(filterQueryKey); v != "" {
			f, err := query.ParseFiltering(v)
			if err != nil {
				return status.Error(codes.InvalidArgument, err.Error())
			}
			err = SetCollectionOps(req, f)
			if err != nil {
				return err
			}
		}
		var p *query.Pagination
		l := vals.Get(limitQueryKey)
		o := vals.Get(offsetQueryKey)
		pt := vals.Get(pageTokenQueryKey)
		p, err = query.ParsePagination(l, o, pt)
		if err != nil {
			return status.Error(codes.InvalidArgument, err.Error())
		}
		err = SetCollectionOps(req, p)
		if err != nil {
			return err
		}
	}
	return invoker(parentCtx, method, req, reply, cc, opts...)
}
func NewGateway(options ...Option) (*http.ServeMux, error) {
	g := gateway{
		serverAddress:     DefaultServerAddress,
		endpoints:         make(map[string][]registerFunc),
		serverDialOptions: []grpc.DialOption{grpc.WithInsecure(), grpc.WithUnaryInterceptor(ClientUnaryInterceptor)},
		mux:               http.NewServeMux(),
	}
	for _, opt := range options {
		opt(&g)
	}
	return g.registerEndpoints()
}
func (g gateway) registerEndpoints() (*http.ServeMux, error) {
	for prefix, registers := range g.endpoints {
		gwmux := runtime.NewServeMux(
			append([]runtime.ServeMuxOption{runtime.WithErrorHandler(ProtoMessageErrorHandler),
				runtime.WithMetadata(MetadataAnnotator)}, g.gatewayMuxOptions...)...,
		)
		for _, register := range registers {
			if err := register(
				context.Background(), gwmux, g.serverAddress, g.serverDialOptions,
			); err != nil {
				return nil, err
			}
		}
		g.mux.Handle(prefix, http.StripPrefix(prefix[:len(prefix)-1], gwmux))
	}
	return g.mux, nil
}
func WithDialOptions(options ...grpc.DialOption) Option {
	return func(g *gateway) {
		g.serverDialOptions = options
	}
}
func WithEndpointRegistration(prefix string, endpoints ...registerFunc) Option {
	return func(g *gateway) {
		g.endpoints[prefix] = append(g.endpoints[prefix], endpoints...)
	}
}
func WithServerAddress(address string) Option {
	return func(g *gateway) {
		g.serverAddress = address
	}
}
func WithMux(mux *http.ServeMux) Option {
	return func(g *gateway) {
		g.mux = mux
	}
}