github.com/renbou/grpcbridge@v0.0.2-0.20240416012907-bcbd8b12648a/bridge.go (about) 1 package grpcbridge 2 3 import ( 4 "log/slog" 5 "net/http" 6 7 "github.com/renbou/grpcbridge/bridgelog" 8 "github.com/renbou/grpcbridge/routing" 9 "github.com/renbou/grpcbridge/transcoding" 10 "github.com/renbou/grpcbridge/webbridge" 11 ) 12 13 var _ = slog.Logger{} 14 15 // Option configures common grpcbridge options, such as the logger. 16 type Option interface { 17 RouterOption 18 ProxyOption 19 BridgeOption 20 } 21 22 // Router unifies the [routing.GRPCRouter] and [routing.HTTPRouter] interfaces, 23 // providing routing support for both [GRPCProxy] and [WebBridge] for all kinds of incoming calls. 24 // It is implemented by [ReflectionRouter], which is the default routing component used by grpcbridge itself. 25 type Router interface { 26 routing.GRPCRouter 27 routing.HTTPRouter 28 } 29 30 // BridgeOption configures the various bridging handlers used by [WebBridge]. 31 type BridgeOption interface { 32 applyBridge(o *bridgeOptions) 33 } 34 35 // WebBridge provides a single entrypoint for all web-originating requests which are bridged to target gRPC services with various applied transformations. 36 type WebBridge struct { 37 transcodedHTTPBridge *webbridge.TranscodedHTTPBridge 38 } 39 40 // NewWebBridge constructs a new [*WebBridge] with the given router and options. 41 // When no options are provided, the [transcoding.StandardTranscoder] and the 42 // underlying bridge handlers from [webbridge] will be initialized with their default options. 43 func NewWebBridge(router Router, opts ...BridgeOption) *WebBridge { 44 options := defaultBridgeOptions() 45 46 for _, opt := range opts { 47 opt.applyBridge(&options) 48 } 49 50 transcoder := transcoding.NewStandardTranscoder(options.transcoderOpts) 51 transcodedHTTPBridge := webbridge.NewTranscodedHTTPBridge(router, transcoder, webbridge.TranscodedHTTPBridgeOpts{Logger: options.common.logger}) 52 53 return &WebBridge{transcodedHTTPBridge: transcodedHTTPBridge} 54 } 55 56 // ServeHTTP implements [net/http.Handler] and routes the request to the appropriate bridging handler according to these rules: 57 // 1. All requests are currently handled by [webbridge.TranscodedHTTPBridge]. 58 func (b *WebBridge) ServeHTTP(w http.ResponseWriter, r *http.Request) { 59 b.transcodedHTTPBridge.ServeHTTP(w, r) 60 } 61 62 // WithMarshalers allows using custom marshalers for transcoding-based handlers, 63 // which will be picked according to the content types they support. 64 // By default, [transcoding.DefaultJSONMarshaler] is used. 65 func WithMarshalers(marshalers []transcoding.Marshaler) BridgeOption { 66 return newFuncBridgeOption(func(o *bridgeOptions) { 67 o.transcoderOpts.Marshalers = marshalers 68 }) 69 } 70 71 // WithDefaultMarshaler allows setting a custom default marshaler for transcoding-based handlers, 72 // which will be used for requests which do not specify the Content-Type header. 73 // By default, [transcoding.DefaultJSONMarshaler] is used. 74 func WithDefaultMarshaler(m transcoding.Marshaler) BridgeOption { 75 return newFuncBridgeOption(func(o *bridgeOptions) { 76 o.transcoderOpts.DefaultMarshaler = m 77 }) 78 } 79 80 // WithLogger configures the logger to be used by grpcbridge components. By default all logs are discarded. 81 // 82 // Taking the full Logger interface allows you to configure all functionality however you want, 83 // however you can also use [bridgelog.WrapPlainLogger] to wrap a basic logger such as [slog.Logger]. 84 func WithLogger(logger bridgelog.Logger) Option { 85 return newFuncOption(func(o *options) { 86 o.logger = logger 87 }) 88 } 89 90 type options struct { 91 logger bridgelog.Logger 92 } 93 94 func defaultOptions() options { 95 return options{logger: bridgelog.Discard()} 96 } 97 98 type funcOption struct { 99 f func(*options) 100 } 101 102 func (f *funcOption) applyRouter(o *routerOptions) { 103 f.f(&o.common) 104 } 105 106 func (f *funcOption) applyProxy(o *proxyOptions) { 107 f.f(&o.common) 108 } 109 110 func (f *funcOption) applyBridge(o *bridgeOptions) { 111 f.f(&o.common) 112 } 113 114 func newFuncOption(f func(*options)) Option { 115 return &funcOption{f: f} 116 } 117 118 type bridgeOptions struct { 119 common options 120 transcoderOpts transcoding.StandardTranscoderOpts 121 } 122 123 func defaultBridgeOptions() bridgeOptions { 124 return bridgeOptions{common: defaultOptions()} 125 } 126 127 type funcBridgeOption struct { 128 f func(*bridgeOptions) 129 } 130 131 func (f *funcBridgeOption) applyBridge(o *bridgeOptions) { 132 f.f(o) 133 } 134 135 func newFuncBridgeOption(f func(*bridgeOptions)) BridgeOption { 136 return &funcBridgeOption{f: f} 137 }