3 ms·
Posted this on the blog as well, but some here might find it useful. Instead of duplicating code to implement common/middleware functionality, I like to just p
by abtinf 12y ago
Posted this on the blog as well, but some here might find it useful.
Instead of duplicating code to implement common/middleware functionality, I like to just pass around functions. I usually just have one makeStandardHandler type function that covers most cases. For the special cases, I can easily combine middleware in any order for the desired result.
// Execution timing middleware
func makeTimingHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
requestStartTime := time.Now()
fn(w, r)
totalRequestTime := time.Now().Sub(requestStartTime)
log.Printf("URL: %s TIME: %s", r.URL.Path, totalRequestTime.String())
}
}
// Serve up one file
func makeSingleFileHandler(file string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, file)
}
}
func main() {
...
http.HandleFunc("/robots.txt", makeTimingHandler(makeSingleFileHandler("./s/robots.txt")))
http.HandleFunc("/", makeTimingHandler(indexHandler))
...
}
- digitaltoad 12y agoDepending on the complexity of the app, I feel like this way of handling middleware can get out of hand.
- elithrar 12y ago> Instead of duplicating code to implement common/middleware functionality, I like to just pass around functions. The problem there is that it doesn't allow you to either: • Apply the middleware to routers or sub-routers; • You end up with http.HandleFunc("/", loggingMiddleware(recoveryMiddleware(sessionMiddleware(myHandler)))) - which is no fun, repetitive and prone to errors • There's no request context - your handlers have no way to communicate between themselves (i.e. passing a CSRF token from middleware to the handler rendering the template or writing to the response header) It does work for basic applications, but it just doesn't scale beyond more than a (small) handful of routes. I wrote a little function[1] that helps with avoiding the gratuitous function nesting, but you'll need to BYO request context in many cases. This often ends up being map[string]interface{} (so you may want getters/setters to wrap types coming in and out), as the alternative is to rely on structs + methods (ala https://github.com/gocraft/web https://github.com/gocraft/web) which can be a little unwieldy. Horses for courses, as they say! [1]: https://gist.github.com/elithrar/21cb76b8e29398722532 https://gist.github.com/elithrar/21cb76b8e29398722532