Continue the idea of wrapping
- The interface
http.Handler
allows to wrap any HTTP handler easily
- This way it’s ideal to separate functional and non-functional code
- While our own handlers take care for the business logic wrappers like
httpx.MethodHandler
and httpx.NestedMux
take care for the HTTP logic
- This can be continued with other aspects of the application, like the logging
HTTPX
package httpx
import (
"net/http"
)
// Logger defines an interface for many different loggers. So e.g.
// the log.Logger from the standard library or the logrus.Logger can
// be used.
type Logger interface {
Printf(format string, v ...interface{})
}
// LoggingHandler wraps handlers and logs the requests to them.
type LoggingHandler struct {
logger Logger
handler http.Handler
}
// NewLoggingHandler creates a new logging handler with the given logger and handler.
func NewLoggingHandler(logger Logger, handler http.Handler) *LoggingHandler {
return &LoggingHandler{
logger: logger,
handler: handler,
}
}
// ServeHTTP logs the request and calls the wrapped handler.
func (h *LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.logger.Printf("%s %s", r.Method, r.URL.Path)
h.handler.ServeHTTP(w, r)
}
Example
NestedMux
wraps several business logic handlers
LoggingHandler
wraps the NestedMux
and logs the requests
ServeMux
wraps the LoggingHandler
and serves all requests
package main
import (
"log"
"net/http"
"os"
"./pkg/httpx"
"./pkg/user"
)
const (
// Prefix for API calls.
apiPrefix = "/api/v1"
)
func main() {
mux := http.NewServeMux()
apimux := httpx.NewNestedMux(apiPrefix)
apilogger := httpx.NewLoggingHandler(log.New(os.Stdout, "api: ", log.LstdFlags), apimux)
apimux.Handle("users", httpx.MethodWrapper(user.NewUsersHandler()))
apimux.Handle("users/addresses", httpx.MethodWrapper(user.NewUsersAddressesHandler()))
apimux.Handle("users/contracts", httpx.MethodWrapper(user.NewUsersContractsHandler()))
// Register further nested API handlers, then
// let the multiplexer serve all API requests.
mux.Handle(apiPrefix, apilogger)
// Register further multiplexed handlers, e.g. for static files.
http.ListenAndServe(":8080", mux)
}
Links