Skip to content

proposal: net/http: add RoundTripperFunc and Middleware for server & client #38479

Open
@leaxoy

Description

@leaxoy

Now, in net/http, for server side, we have Handler & HandlerFunc, HandlerFunc is the convenient way for user to define new handler, but in client side, we only have RoundTripper, so I proposal to add RoundTripperFunc to net/http.

// RoundTripperFn implement http.RoundTripper for convenient usage.
type RoundTripperFunc func(request *http.Request) (*http.Response, error)
func (fn RoundTripperFunc) RoundTrip(request *http.Request) (*http.Response, error) { return fn(request) }

With this new type, we can easily implement RoundTripper interface.

In modern web application, middleware pattern is widely used. With Middleware we can add more action before/after handler/request call.
For the server side, we can define Middleware or similar:

type Middleware interface {
	Next(h http.Handler) http.Handler
}

// MiddlewareFn support wrap function with same signature as Middleware.
type MiddlewareFn func(h http.Handler) http.Handler

func (fn MiddlewareFn) Next(h http.Handler) http.Handler { return fn(h) }

// and compose chains of middleware
// ComposeInterceptor compose interceptors to given http.RoundTripper
func ComposeInterceptor(rt http.RoundTripper, interceptors ...Interceptor) http.RoundTripper {
	if len(interceptors) == 0 {
		return rt
	}
	return ComposeInterceptor(interceptors[0].Next(rt), interceptors[1:]...)
}

For the client side, we define Interceptor or similar:

type Interceptor interface {
	Next(fn http.RoundTripper) http.RoundTripper
}

// InterceptorFn implement Interceptor for convenient usage.
type InterceptorFn func(rt http.RoundTripper) http.RoundTripper

func (fn InterceptorFn) Next(rt http.RoundTripper) http.RoundTripper { return fn(rt) }

// and a function compose chains of interceptor
func ComposeInterceptor(rt http.RoundTripper, interceptors ...Interceptor) http.RoundTripper {
	if len(interceptors) == 0 {
		return rt
	}
	return ComposeInterceptor(interceptors[0].Next(rt), interceptors[1:]...)
}

All the above are not necessary, but can reduce and simplify user's boilerplate code.
Please consider this proposal.

The original code is middleware, interceptor & RoundTripperFunc

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions