I am familiar with the Go middleware pattern like this:
// Pattern for writing HTTP middleware.
func middlewareHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Our middleware logic goes here before executing application handler.
next.ServeHTTP(w, r)
// Our middleware logic goes here after executing application handler.
})
}
So for example if I had a loggingHandler:
func loggingHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Before executing the handler.
start := time.Now()
log.Printf("Strated %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
// After executing the handler.
log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
})
}
And a simple handleFunc:
func handleFunc(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`Hello World!`))
}
I could combine them like this:
http.Handle("/", loggingHandler(http.HandlerFunc(handleFunc)))
log.Fatal(http.ListenAndServe(":8080", nil))
That is all fine.
But I like the idea of Handlers being able to return errors like normal functions do. This makes error handling much easier as I can just return an error if there is an error, or just return nil at the end of the function.
I have done it like this:
type errorHandler func(http.ResponseWriter, *http.Request) error
func (f errorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := f(w, r)
if err != nil {
// log.Println(err)
fmt.Println(err)
os.Exit(1)
}
}
func errorHandle(w http.ResponseWriter, r *http.Request) error {
w.Write([]byte(`Hello World from errorHandle!`))
return nil
}
And then use it by wrapping it like this:
http.Handle("/", errorHandler(errorHandle))
I can make these two patterns work separately, but I don't know how I could combine them. I like that I am able to chain middlewares with a library like Alice. But it would be nice if they could return errors too. Is there a way for me to achieve this?