Your Code a Mess? Maybe it’s time to bring in the Decorators

How to apply decorators to Go code with two simple examples

Decorators in Go

In computer science a decorator is pattern for adding functionality (i.e. logging, authentication) to another function by wrapping it.

This is really useful for web handlers, but is also poorly documented in Go and has resulted in a miriad of middleware libraries being created, which, in my humble opinion, tend to be overkill for such a simple requirement.

In any language you should never wander far from the standard library, if the situation doesn’t warrant it and you should always avoid re-inventing the wheel.

It is so simple to decorate functions in Python, I couldn’t believe that it would be so difficult to replicate this functionality in Go.

After ardous hours of googling I found a great example by Alex Alehano, that shows the most concise example, can be easily applied to http handlers in GO and this is the result.

Decorating a simple function Example

This example decorates the ‘myFunction’ function with simple logger:

  1. package main
  2. import (
  3. "log"
  4. "fmt"
  5. )
  6. func decorator(fn func(s string)) func(s string) {
  7. return func(s string) {
  8. log.Println("starting")
  9. fn(s)
  10. log.Println("completed")
  11. }
  12. }
  13. func myFunction(s string) {
  14. fmt.Println(s)
  15. }
  16. func main() {
  17. f := decorator(myFunction)
  18. f("Hello Decorator")
  19. // or decorator(myFunction)("Hello Decorator")
  20. }

Applying decorators to the Standard Libraries’ HTTP Package

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. )
  7. func simpleHandler(w http.ResponseWriter, r *http.Request) {
  8. fmt.Fprint(w, "Hello World")
  9. }
  10. func decorator(f http.HandlerFunc) http.HandlerFunc {
  11. return func(w http.ResponseWriter, r *http.Request) {
  12. // Do extra stuff here, e.g. check API keys in header,
  13. // restrict hosts etc
  14. log.Println("Started", r.)
  15. f(w, r) // call function here
  16. log.Println("Done")
  17. }
  18. }
  19. func main() {
  20. http.HandleFunc("/decorated", decorator(simpleHandler))
  21. http.HandleFunc("/notdecorated", simpleHandler)
  22. http.ListenAndServe("", nil)
  23. }

This way readable and simplicity are maintained by decorating the handlers in Go, which give the desired functionality without the dreaded code bloat.

ft_authoradmin  ft_create_time2018-04-28 14:27
 ft_update_time2018-04-28 14:29