Gon
Gon

Reputation: 733

Add response header to every handler without repeating the same line

I am writing a small website and for every page, I am putting a server name to its header:

func httpSignUp(rw http.ResponseWriter, req *http.Request) {
    rw.Header().Set("Server", SERVER_NAME)
}

I am wondering if there's a way that I can set http.ResponseWriter's default server name, so I don't have to use the same line over and over?

Upvotes: 4

Views: 2224

Answers (3)

Roy Lee
Roy Lee

Reputation: 10862

"Prefer composition to inheritance" - Gang of 4

Inheritance simply wasn't designed into Golang in the first place. ;)

If you are looking for detailed explanations on the why part, I believed this has been answered on SO, hence I would just point you to it: Embedding instead of inheritance in Go.

Well, you can actually achieve the same result with adapter design pattern, which enables you to extend functionality from a built-in library, and to me, its way more flexible than inheritance.

func adapter(h http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Server", SERVER_NAME)
    h.ServeHTTP(w, r)
  })
}

Or pass in serverName as parameter:

func adapter(h http.Handler, serverName string) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Server", serverName)
    h.ServeHTTP(w, r)
  })
}

Finally, you have the flexibility to choose which handler(s) to be 'inherited':

http.Handle("/path", adapter(your_handler))

Or if its meant for every handlers, just 'inherit' to the root-handler:

http.ListenAndServe(port, adapter(root_Handler))

Upvotes: 3

Thundercat
Thundercat

Reputation: 121169

Create a wrapper to set the header:

func wrap(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (
         w.Header().Set("Server", SERVER_NAME)
         h.ServeHTTP(w, r)
    })
}

Wrap individual handlers

http.Handle("/path", wrap(aHandler)(
http.Handle("/another/path", wrap(anotherHandler))

or the root handler passed to ListenAndServe:

log.Fatal(http.ListenAndServe(addr, wrap(rootHandler))

Upvotes: 11

Parth Desai
Parth Desai

Reputation: 1839

The http.ResponseWriter is an interface, not a struct. So, You cannot extend it directly. You need to extend the internal struct. But it is not idiomatic way to solve this problem.

One approach you can take is to use middleware. middleware is just a piece of code which will be executed before your main request handler, and can be used perform some common tasks.

For example, to write the same thing using middleware approach:

func injectServerHeader(handler http.Handler, serverName string) http.Handler {
    ourFunc := func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Server", serverName)
        handler.ServeHTTP(w, r)
    }
    return http.HandlerFunc(ourFunc)
}

This way, you wrap your actual http handler with middleware. So, you won't have to write same code over and over again.

For example:

http.Handle("/some-path", injectServerHeader(aHandler))

Upvotes: 3

Related Questions