The general process of error handling in net/http is as follows:
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /hello", helloHandler)
http.ListenAndServe(":8080", mux)
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
condition := false
if !condition {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "hello world")
}Imagine you want to add centralized error handling when using net/http.
In that case, helloHandler must return an error:
func helloHandlerWithErr(w http.ResponseWriter, r *http.Request) error {
condition := false
if !condition {
return fmt.Errorf("condition is false")
}
fmt.Fprintf(w, "hello world")
return nil
}However, http.HandleFunc only accepts handler functions with the signature func(http.ResponseWriter, *http.Request):
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))You thought of writing an adapter to convert
type HandlerFunc func(http.ResponseWriter, *http.Request) errorinto
type HttpHandlerFunc func(http.ResponseWriter, *http.Request)You implement centralized error handling in the adapter:
func Adapter(fn HandlerFunc) HttpHandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
err := fn(w, r)
// Centralized error handling
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}
}You have implemented centralized error handling, but you need to wrap each HandlerFunc with Adapter:
mux.HandleFunc("GET /hello", Adapter(helloHandlerWithErr))This is cumbersome, and we need to further optimize it.
Create a struct ServeMux that embeds http.ServeMux:
type ServeMux struct {
http.ServeMux
}Override the HandleFunc method of ServeMux to accept HandlerFunc instead of the original HttpHandlerFunc:
func (m *ServeMux) HandleFunc(pattern string, handler HandlerFunc) {
m.ServeMux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
err := handler(w, r)
if err != nil {
http.Error(w, "some msg", http.StatusBadRequest)
}
})
}This way, you don’t need to use Adapter for wrapping. The complete implementation is available at
https://github.com/aeilang/httpz/blob/main/http.go