I am trying to grasp (and sofar failing) to exactly grasp how the following code example works. It wraps (decorates) a standard http.client with 2 middleware functions (Logger and BasicAuth) that are invoked when making client (RoundTripper) calls. The setup/initialization is as follows:
package decorator
import (
"log"
"net/http"
"os"
)
// Setup initializes our ClientInterface
func Setup() *http.Client {
c := http.Client{}
t := Decorate(&http.Transport{},
Logger(log.New(os.Stdout, "", 0)),
BasicAuth("username", "password"),
)
c.Transport = t
return &c
}
The problem is that I dont exactly understand what happens in the Decorate function.
The whole file containing the function is as follows:
package decorator
import "net/http"
// TransportFunc implements the RountTripper interface
type TransportFunc func(*http.Request) (*http.Response, error)
// RoundTrip just calls the original function
func (tf TransportFunc) RoundTrip(r *http.Request) (*http.Response, error) {
return tf(r)
}
// Decorator is a convenience function to represent our
// middleware inner function
type Decorator func(http.RoundTripper) http.RoundTripper
// Decorate is a helper to wrap all the middleware
func Decorate(t http.RoundTripper, rts ...Decorator) http.RoundTripper {
decorated := t
for _, rt := range rts {
decorated = rt(decorated)
}
return decorated
}
The 2 middleware functions are defined as follows:
package decorator
import (
"log"
"net/http"
"time"
)
// Logger is one of our 'middleware' decorators
func Logger(l *log.Logger) Decorator {
return func(c http.RoundTripper) http.RoundTripper {
return TransportFunc(func(r *http.Request) (*http.Response, error) {
start := time.Now()
l.Printf("started request to %s at %s", r.URL, start.Format("2006-01-02 15:04:05"))
resp, err := c.RoundTrip(r)
l.Printf("completed request to %s in %s", r.URL, time.Since(start))
return resp, err
})
}
}
// BasicAuth is another of our 'middleware' decorators
func BasicAuth(username, password string) Decorator {
return func(c http.RoundTripper) http.RoundTripper {
return TransportFunc(func(r *http.Request) (*http.Response, error) {
r.SetBasicAuth(username, password)
resp, err := c.RoundTrip(r)
return resp, err
})
}
}
I understand that in Setup() the Transport of the http.Client is augmented with "configuration" of the 2 middleware functions but don't understand how the "Decorate" functions works and how the decorators exactly are added to the transport. (I see in the debugger that under var t at some point in time there is a \data struct that seems to include references to the logger function and the user/password combination but have no idea where this \data comes from)
Hope this describes my problem fully if not please ask for additional info
thanks