I'm not familiar with go-chi, but for any kind of middlewares in any language the pattern is almost the same
In your case you should write something like this:
func CustomMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// your custom logic before request processing started
next.Handle(w, r)
// your custom logic after request processed
})
}
To make the example more expressive, let's write a middleware for writing metrics
type MetricsHandler interface {
Increment(key string, tags ...string)
}
type responseWrapper struct {
http.ResponseWriter
statusCode int
}
func (r *responseWrapper) WriteHeader(statusCode int) {
r.statusCode = statusCode
r.ResponseWriter.WriteHeader(statusCode)
}
func MetricsMiddleware(m MetricsHandler) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tags := []string{"path", request.URL.Path}
m.Increment("requests.incoming.count", tags...)
response := &responseWrapper{w}
defer func() {
if response.statusCode < http.StatusBadRequest {
m.Increment("requests.incoming.processed", tags...)
} else {
m.Increment("requests.incoming.failed", tags...)
}
}()
next.Handle(response, r)
})
}
}
And now you can use this middleware in your application and metrics will be sent with tags for each endpoint