Here is the complete example from my current reading material "Hands-On Restful Web Services With Go" from Packt.
func filterContentType(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("Currently in the check content type middleware")
// Filtering requests by MIME type
if r.Header.Get("Content-type") != "application/json" {
w.WriteHeader(http.StatusUnsupportedMediaType)
w.Write([]byte("415 - Unsupported Media Type. Please send JSON"))
return
}
handler.ServeHTTP(w, r)
})
}
func setServerTimeCookie(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Setting cookie to every API response
cookie := http.Cookie{Name: "ServerTimeUTC", Value: strconv.FormatInt(time.Now().Unix(), 10)}
http.SetCookie(w, &cookie)
log.Println("Currently in the set server time middleware")
handler.ServeHTTP(w, r)
})
}
func handle(w http.ResponseWriter, r *http.Request) {
// Check if method is POST
if r.Method == "POST" {
var tempCity city
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&tempCity)
if err != nil {
panic(err)
}
defer r.Body.Close()
// Your resource creation logic goes here. For now it is plain print to console
log.Printf("Got %s city with area of %d sq miles!\n", tempCity.Name, tempCity.Area)
// Tell everything is fine
w.WriteHeader(http.StatusOK)
w.Write([]byte("201 - Created"))
} else {
// Say method not allowed
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("405 - Method Not Allowed"))
}
}
func main() {
originalHandler := http.HandlerFunc(handle)
http.Handle("/city", filterContentType(setServerTimeCookie(originalHandler))) // !
http.ListenAndServe(":8000", nil)
}
This program simply consists of the main function and 3 other functions, their logic is arbitrary and just copied from my book's example.
At bottom, where I've commented with "!", filterContentType is using an argument that itself is a function (setServerTimeCookie), and it looks like it's being invoked with originalHandler as its argument.
However when this code is run, the order of execution is:
filterContentType 2. setServerTimeCookie 3. originalHandler
This is counterintuitive to what I understand about using functions as arguments. I assumed that setServerTimeCookie would be the first to execute but that's not the case; it's behaving like an uninvoked function.
This leads to my question, what is causing setServerTimeCookie to defer its execution despite the syntax suggesting it's being invoked as filterContentType's argument?
I attempted to simplify things for my own understanding:
func main() {
one(two(three))
}
func one(f func()) {
fmt.Println("ONE\n")
f()
}
func two(f func()) {
fmt.Println("TWO\n")
f()
}
func three(){
fmt.Println("THREE\n")
}
This code does not build, I'm left with the error:
two(three) used as value -which tells me that two is being invoked, unlike the book's example.
What's the difference and again, why doesn't the book's example invoke setServerTimeCookie first? My only assumption is that it has something to do with the implementation of http.HandlerFunc so maybe I should start there.
Any insight to fast-forward my understanding would be greatly appreciated.
This doesn't compile because two(three) does not return a value.
I assume you want to return a function closure in this case, so to fix:
func two(f func()) func() {
return func() {
fmt.Println("TWO\n")
f()
}
}
https://go.dev/play/p/vBrAO6nwy4X
Circling back to your question about setServerTimeCookie and it's use of return http.HandlerFunc(fn). Looking at the source for http.HandlerFunc reveals it's actually a type definition - and NOT a conventional function call. It's actual IMHO the most powerful and underrated four lines of code in the go standard library:
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
By creating this value of http.HandlerFunc, it's implicitly a http.Handler, since it provides the ServeHTTP method. This therefore allows this method to be called upon request - which is exactly what a webservice is designed to do: the underlying function f will be invoked when the handler is invoked.
Because in the expression one(two(three)) function two is not passed as function reference. Instead function two is called with the argument tree, which is not what function one expects
Related
I am new to GoLang and working on my first API. I have two endpoints, and I want to rate limit only one of them. I found a helpful tutorial to get me started, and I've based my approach off of the tutorial, recognizing that this approach will rate limit both of my endpoints:
var limiter = rate.NewLimiter(rate.Every((1*time.Hour)/3), 1)
func limit(next http.Handler) http.Handler {
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
if limiter.Allow() == false {
http.Error(res, http.StatusText(429), http.StatusTooManyRequests)
return
}
next.ServeHTTP(res, req)
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", createNewToken)
mux.HandleFunc("/notify", sendPushNotificationToAllTokens)
log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", limit(mux)))
}
I researched the difference between http.Handle and http.HandleFunc and naively believed that I could substitute http.HandleFunc for http.Handle. This approach is completely flawed as the logic contained in the HandlerFunc never executes:
var limiter = rate.NewLimiter(rate.Every(1*time.Hour/3), 1)
func limit(next http.HandlerFunc) http.HandlerFunc {
return func(res http.ResponseWriter, req *http.Request) {
if limiter.Allow() == false {
http.Error(res, http.StatusText(429), http.StatusTooManyRequests)
return
}
next.ServeHTTP(res, req)
}
}
func main() {
//mux := http.NewServeMux()
http.HandleFunc("/", createNewToken)
http.HandleFunc("/notify", sendPushNotificationToAllTokens)
// attempt to only rate limit the /notify endpoint
log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", limit(sendPushNotificationToAllTokens)))
Can anyone explain why this does not work, and how I could approach this problem to only rate limit a specific endpoint?
The distinction between using a plain http.Handler and a http.HanlderFunc doesn't really matter here. http.HandleFunc is just a way to convert a regular function into a http.Handler - it essentially does the same thing as your original version of limit.
Your implementations of limit both look fine; probably the second is better because it's simpler. Instead, the issue is in main. When you call http.ListenAndServeTLS and provide a value for the final argument, it requests that only the handler you pass in as that final argument be used as the root request handler. Any calls to http.Handle() or http.HandleFunc() are ignored unless you pass in nil as this final argument.
What you want to do instead is apply limit to the specific handler you want to limit. You have two options for this. First, you can use a ServeMux like in your first code snippet:
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", createNewToken)
// Limit only the handler for "/notify".
mux.HandleFunc("/notify", limit(sendPushNotificationToAllTokens))
// Don't limit the whole mux.
log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", mux))
}
Alternatively, you can do something more like your second code snippet, but pass in nil for the final argument to http.ListenAndServeTLS so that the default http.ServeMux is used, meaning that the calls to http.HandleFunc() will be respected:
func main() {
http.HandleFunc("/", createNewToken)
// Limit only the handler for "/notify".
http.HandleFunc("/notify", limit(sendPushNotificationToAllTokens))
// Pass in nil here so that http.DefaultServeMux is used.
log.Fatal(http.ListenAndServeTLS(":5050", "localhost.crt", "localhost.key", nil))
}
For a simple application, the first approach is probably fine. For anything more complex, I'd recommend the later approach because it will work if you open multiple servers or do other more complex things.
I'm writing an HTTP service in Go using Gorilla. I'm newish to Go (<1yr experience), but ramping up fairly quickly.
I have a function I use to register my handlers:
func (s *Server) RegisterHandler(path string, handler http.HandlerFunc, methods ...string) {
if len(methods) == 0 {
s.Router.Handle(path, handler).Methods(http.MethodGet)
} else {
s.Router.Handle(path, handler).Methods(methods...)
}
}
I have some code that registers named functions as handlers:
func (s *Server) RegisterDefaultHandlers() {
s.RegisterHandler("/ping", Ping)
}
func Ping(w http.ResponseWriter, request *http.Request) {
responders.RespondOk(w)
}
I also have unit test code that registers anonymous functions as handlers:
s.RegisterHandler("/testPath", func(w http.ResponseWriter, r *http.Request) {
// whatever the test calls for
}, http.MethodPost)
This all works great -- just establishing my starting point.
Today, I find myself banging my head against Go's type system. I am defining some custom handler types, for example:
type UserAwareHandlerFunc func(http.ResponseWriter, *http.Request, models.User)
And I'm also introducing a function to allow me to register such handlers, and to wrap all handlers in context.ClearHandler. If this works, I'll also wrap everything with another function that sets a few things on my logging context. What I have so far:
func (s *Server) RegisterHandler(path string, handler interface{}, methods ...string) {
wrappedHandler := wrappers.ApplyWrappers(handler)
if len(methods) == 0 {
s.Router.Handle(path, wrappedHandler).Methods(http.MethodGet)
} else {
s.Router.Handle(path, wrappedHandler).Methods(methods...)
}
}
func ApplyWrappers(handler interface{}) http.Handler {
var result http.Handler
if userAwareHandler, ok := handler.(UserAwareHandlerFunc); ok {
result = UserAware(userAwareHandler)
} else if handlerFunc, ok := handler.(http.HandlerFunc); ok {
result = handlerFunc
} else if handlerObj, ok := handler.(http.Handler); ok {
result = handlerObj
} else {
log.Fatalf("handler %+v (type %s) is not a recognized handler type.", handler, reflect.TypeOf(handler))
}
// to avoid memory leaks, ensure that all request data is cleared by the end of the request lifetime
// for all handlers -- see https://stackoverflow.com/a/48203334
result = context.ClearHandler(result)
return result
}
func UserAware(handler UserAwareHandlerFunc) http.Handler {
return func(w http.ResponseWriter, r *http.Request) {
user := ... // get user from session
handler(w, r, user)
}
}
With these changes, I can no longer register named or anonymous functions; the type assertions in ApplyWrappers all fail. I have to declare and define a typed variable, then pass that in.
Named functions have two feasible approaches:
var Ping http.HandlerFunc = func(w http.ResponseWriter, request *http.Request) {
responders.RespondOk(w)
}
func Ping2(w http.ResponseWriter, request *http.Request) {
responders.RespondOk(w)
}
func (s *Server) RegisterDefaultHandlers() {
s.RegisterHandler("/ping", Ping)
var pingHandler2 http.HandlerFunc = Ping2
s.RegisterHandler("/ping2", pingHandler2)
}
For anonymous functions, I can do:
var handler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
...
}
s.RegisterHandler("/testPath", handler, http.MethodPost)
The whole point of what I've built here is to consolidate boilerplate into one place, keeping my many tests and handlers as streamlined as possible. The need to declare a typed variable is working against that goal. So my question is this: is there some special type magic I could use (preferably in RegisterHandler and/or ApplyWrappers) that would restore the ability to pass named and/or anonymous functions to RegisterHandler?
EDIT: thanks so much for the quick answers. Problem solved:
func ApplyWrappers(handler interface{}) http.Handler {
var result http.Handler
if userAwareHandler, ok := handler.(UserAwareHandlerFunc); ok {
result = UserAware(userAwareHandler)
} else if anonymousFunc, ok := handler.(func(http.ResponseWriter,*http.Request)); ok {
result = http.HandlerFunc(anonymousFunc)
} else if handlerObj, ok := handler.(http.Handler); ok {
result = handlerObj
} else {
log.Fatalf("handler %+v (type %s) is not a recognized handler type.", handler, reflect.TypeOf(handler))
}
// to avoid memory leaks, ensure that all request data is cleared by the end of the request lifetime
// for all handlers -- see https://stackoverflow.com/a/48203334
result = context.ClearHandler(result)
return result
}
It's working now, but I still have questions:
If I understand correctly, the "duck typing" behavior that I was looking for here would have been fine if I were dealing with interfaces rather than functions. What drives the distinction? Is duck-typing of functions something I could reasonably hope to see in a future version of the language?
I can cast the anonymous function to a HandlerFunc. It's weird to me that casting and type assertions don't share semantics. Can someone explain?
EDIT 2: I've now seen the bit of the language spec that says that defined types (i.e. ones with names) are never identical to any other type, even if the underlying type is the same, and as such will never work in a type assertion (unless it's an interface). So now I'm left wondering:
Why are the semantics different between interfaces and other types?
Why are the semantics different for named and un-named types?
I find both to be unintuitive and inconvenient. Am I alone here? I'm wondering if anyone knows why these decisions were made when the language was designed (perhaps it's particularly difficult to implement without bloating the compiler or its output, etc.), and if anyone is aware of plans to address either situation.
http.HandlerFunc is a specific type. The Ping function is NOT of that type, although it can be converted to that type since they both have the same underlying type.
If handler is an anonymous function then you need to use an anonymous function in the type assertion:
f, ok := handler.(func(http.ResponseWriter,*http.Request))
https://golang.org/ref/spec#Type_assertions
if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T
If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T.
I am designing my handlers to return a http.Handler. Here's the design of my handlers:
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
})
}
My middleware is designed to accept an http.Handler and then call the handler once the middleware has finished performing its operations. Here's the design of my middleware:
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
next.ServeHTTP(w, r)
})
}
Considering the design of my middleware and handlers, what is the proper way of passing information from the middleware to the handler? The information that I am trying to pass from my middleware to the handlers is a JSON web token parsed from the request body. If I do not pass the parsed JWT to the handler, then I will need to parse the JWT again in my handlers. Parsing the request body for a JWT in both the middleware and handler seems wasteful. Just in case this information is relevant, I am using the standard net/http library with gorilla mux.
Since you're already using Gorilla take a look at the context package.
(This is nice if you don't want to change your method signatures.)
import (
"github.com/gorilla/context"
)
...
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
// Parse body/get token.
context.Set(r, "token", token)
next.ServeHTTP(w, r)
})
}
...
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := context.Get(r, "token")
})
}
Update
The Gorilla context package is now in maintenance mode
per the repo:
Note gorilla/context, having been born well before context.Context existed, does not play well with the shallow copying of the request that http.Request.WithContext (added to net/http Go 1.7 onwards) performs.
Using gorilla/context may lead to memory leaks under those conditions, as the pointers to each http.Request become "islanded" and will not be cleaned up when the response is sent.
You should use the http.Request.Context() feature in Go 1.7.
The proper way to pass request scoped data would now be the context package in the standard library.
https://golang.org/pkg/context/
You can access it with request.Context on an http.Request.
A first approach, similar to the question, is in codemodus/chain by Daved.
Package chain aids the composition of Handler wrapper chains that carry request-scoped data.
It uses the notion of Context, coupled with a Context handler:
func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// ...
if s, ok := getMyString(ctx); ok {
// s = "Send this down the line."
}
// ...
}
Another approach: You can have a look at "Custom Handlers and Avoiding Globals in Go Web Applications", by Matt Silverlock (elithrar). (full example here)
The idea is to define ServeHTTP on a type which include the relevant context.
// We've turned our original appHandler into a struct with two fields:
// - A function type similar to our original handler type (but that now takes an *appContext)
// - An embedded field of type *appContext
type appHandler struct {
*appContext
h func(*appContext, http.ResponseWriter, *http.Request) (int, error)
}
// Our ServeHTTP method is mostly the same, and also has the ability to
// access our *appContext's fields (templates, loggers, etc.) as well.
func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Updated to pass ah.appContext as a parameter to our handler type.
status, err := ah.h(ah.appContext, w, r)
if err != nil {
log.Printf("HTTP %d: %q", status, err)
switch status {
case http.StatusNotFound:
http.NotFound(w, r)
// And if we wanted a friendlier error page, we can
// now leverage our context instance - e.g.
// err := ah.renderTemplate(w, "http_404.tmpl", nil)
case http.StatusInternalServerError:
http.Error(w, http.StatusText(status), status)
default:
http.Error(w, http.StatusText(status), status)
}
}
}
In the appContext struct, you would put any data you want to pass around.
I am designing my handlers to return a http.Handler. Here's the design of my handlers:
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
})
}
My middleware is designed to accept an http.Handler and then call the handler once the middleware has finished performing its operations. Here's the design of my middleware:
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
next.ServeHTTP(w, r)
})
}
Considering the design of my middleware and handlers, what is the proper way of passing information from the middleware to the handler? The information that I am trying to pass from my middleware to the handlers is a JSON web token parsed from the request body. If I do not pass the parsed JWT to the handler, then I will need to parse the JWT again in my handlers. Parsing the request body for a JWT in both the middleware and handler seems wasteful. Just in case this information is relevant, I am using the standard net/http library with gorilla mux.
Since you're already using Gorilla take a look at the context package.
(This is nice if you don't want to change your method signatures.)
import (
"github.com/gorilla/context"
)
...
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware operations
// Parse body/get token.
context.Set(r, "token", token)
next.ServeHTTP(w, r)
})
}
...
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := context.Get(r, "token")
})
}
Update
The Gorilla context package is now in maintenance mode
per the repo:
Note gorilla/context, having been born well before context.Context existed, does not play well with the shallow copying of the request that http.Request.WithContext (added to net/http Go 1.7 onwards) performs.
Using gorilla/context may lead to memory leaks under those conditions, as the pointers to each http.Request become "islanded" and will not be cleaned up when the response is sent.
You should use the http.Request.Context() feature in Go 1.7.
The proper way to pass request scoped data would now be the context package in the standard library.
https://golang.org/pkg/context/
You can access it with request.Context on an http.Request.
A first approach, similar to the question, is in codemodus/chain by Daved.
Package chain aids the composition of Handler wrapper chains that carry request-scoped data.
It uses the notion of Context, coupled with a Context handler:
func ctxHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// ...
if s, ok := getMyString(ctx); ok {
// s = "Send this down the line."
}
// ...
}
Another approach: You can have a look at "Custom Handlers and Avoiding Globals in Go Web Applications", by Matt Silverlock (elithrar). (full example here)
The idea is to define ServeHTTP on a type which include the relevant context.
// We've turned our original appHandler into a struct with two fields:
// - A function type similar to our original handler type (but that now takes an *appContext)
// - An embedded field of type *appContext
type appHandler struct {
*appContext
h func(*appContext, http.ResponseWriter, *http.Request) (int, error)
}
// Our ServeHTTP method is mostly the same, and also has the ability to
// access our *appContext's fields (templates, loggers, etc.) as well.
func (ah appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Updated to pass ah.appContext as a parameter to our handler type.
status, err := ah.h(ah.appContext, w, r)
if err != nil {
log.Printf("HTTP %d: %q", status, err)
switch status {
case http.StatusNotFound:
http.NotFound(w, r)
// And if we wanted a friendlier error page, we can
// now leverage our context instance - e.g.
// err := ah.renderTemplate(w, "http_404.tmpl", nil)
case http.StatusInternalServerError:
http.Error(w, http.StatusText(status), status)
default:
http.Error(w, http.StatusText(status), status)
}
}
}
In the appContext struct, you would put any data you want to pass around.
I'm trying to set an http header for multiple handlers. My first thought was to make a custom write function that would set the header before writing the response like the code sample at the bottom.
However, when I pass a pointer to the http.ResponseWriter and try to access it from my function it tells me that "type *http.ResponseWriter has no Header method".
What is the best way to set headers for multiple handlers, and also why isn't the pointer working the way I want it to?
func HelloServer(w http.ResponseWriter, req *http.Request) {
type Message struct {
Name string
Body string
Time int64
}
m := Message{"Alice", "Hello", 1294706395881547000}
b, _ := json.Marshal(m)
WriteJSON(&w, b)
}
func WriteJSON(wr *http.ResponseWriter, rawJSON []byte) {
*wr.Header().Set("Content-Type", "application/json")
io.WriteString(*wr, string(rawJSON))
}
func main() {
http.HandleFunc("/json", HelloServer)
err := http.ListenAndServe(":9000", nil)
if err != nil {
log.Fatal("ListenAndServer: ", err)
}
}
I'm not sure about the multiple handlers thing, but I do know why the code you wrote is failing. The key is that the line:
*wr.Header().Set("Content-Type", "application/json")
is being interpreted, because of operator precedence, as:
*(wr.Header().Set("Content-Type", "application/json"))
Since wr has the type *http.ResponseWriter, which is a pointer to and interface, rather than the interface itself, this won't work. I assume that you knew that, which is why you did *wr. I assume what you meant to imply to the compiler is:
(*wr).Header().Set("Content-Type", "application/json")
If I'm not mistaken, that should compile and behave properly.
You don't need to use *wr as it already references a pointer.
wr.Header().Set("Content-Type", "application/json") should be sufficient.
If you want to set "global" headers for every request, you can create a function that satisfies http.HandleFunc (go.auth has a good example) and then wrap your handlers like so:
http.HandleFunc("/hello", Defaults(helloHandler))
Also take a look at the net/http documentation, which has further examples.
I wrap my handlers with an error handler
which calls my AddSafeHeader function.
I based it on http://golang.org/doc/articles/error_handling.html
but it doesn't use ServeHTTP so it works with appstats:
http.Handle("/", appstats.NewHandler(util.ErrorHandler(rootHandler)))
Here:
package httputil
import (
"appengine"
"net/http"
"html/template"
)
func AddSafeHeaders(w http.ResponseWriter) {
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-XSS-Protection", "1; mode=block")
w.Header().Set("X-Frame-Options", "SAMEORIGIN")
w.Header().Set("Strict-Transport-Security", "max-age=2592000; includeSubDomains")
}
// Redirect to a fixed URL
type redirectHandler struct {
url string
code int
}
func (rh *redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Redirect(w, r, rh.url, rh.code)
}
func Redirect(w http.ResponseWriter, r *http.Request, urlStr string, code int) {
AddSafeHeaders(w)
http.Redirect(w, r, urlStr, code)
}
// RedirectHandler returns a request handler that redirects
// each request it receives to the given url using the given
// status code.
func RedirectHandler(url string, code int) http.Handler {
return &redirectHandler{url, code}
}
func ErrorHandler(fn func(appengine.Context, http.ResponseWriter, *http.Request)) func(appengine.Context, http.ResponseWriter, *http.Request) {
return func(c appengine.Context, w http.ResponseWriter, r *http.Request) {
defer func() {
if err, ok := recover().(error); ok {
c.Errorf("%v", err)
w.WriteHeader(http.StatusInternalServerError)
errorTemplate.Execute(w, err)
}
}()
AddSafeHeaders(w)
fn(c, w, r)
}
}
// Check aborts the current execution if err is non-nil.
func Check(err error) {
if err != nil {
panic(err)
}
}
var errorTemplate = template.Must(template.New("error").Parse(errorTemplateHTML))
const errorTemplateHTML = `
<html>
<head>
<title>XXX</title>
</head>
<body>
<h2>An error occurred:</h2>
<p>{{.}}</p>
</body>
</html>
`
http.ResponseWriter is an interface.
You should probably not be using a pointer to an interface. In net/http/server.go, the unexported response struct is the actual type that implements ResponseWriter when the server calls your handler, and importantly, when the server actually calls the handler's ServeHTTP, it passes a *response. It's already a pointer, but you don't see that because ResonseWriter is an interface. (the response pointer is created here, by (c *conn).readRequest. (The links will likely be for the wrong lines the future, but you should be able to locate them).
That's why the ServeHTTP function required to implement Handler is:
ServeHTTP(w ResponseWriter, r *Request)
i.e. not a pointer to ResponseWriter, as this declaration already permits a pointer to a struct that implements the ResponseWriter interface.
As I am new to Go, I created a minimal contrived example, based on elithrar's answer, which shows how to easily add headers to all your routes / responses. We do so, by creating a function that satisfies the http.HandlerFunc interface, then wraps the route handler functions:
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
)
// Hello world.
func Hello(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode("Hello World")
}
// HelloTwo world
func HelloTwo(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode("Hello Two World")
}
// JSONHeaders conforms to the http.HandlerFunc interface, and
// adds the Content-Type: application/json header to each response.
func JSONHeaders(handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
handler(w, r)
}
}
func main() {
router := mux.NewRouter()
// Now, instead of calling your handler function directly, pass it into the wrapper function.
router.HandleFunc("/", JSONHeaders(Hello)).Methods("GET")
router.HandleFunc("/hellotwo", JSONHeaders(HelloTwo)).Methods("GET")
log.Fatal(http.ListenAndServe(":3000", router))
}
Results:
$ go run test.go &
$ curl -i localhost:3000/
HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 28 Feb 2019 22:27:04 GMT
Content-Length: 14
"Hello World"
What i end up doing:
// Accepts a user supplied http.HandlerFunc and then modifies it in various ways. In this case, it adds two new headers.
func CommonlHandler(h http.HandlerFunc) http.HandlerFunc {
return func (rs http.ResponseWriter, rq *http.Request) {
rs.Header().Add("Server", "Some server")
rs.Header().Add("Cache-Control", "no-store")
h(rs, rq)
}
// somewhere down the line, where you're setting up http request handlers
serveMux := http.NewServeMux()
serveMux.HandleFunc("/", CommonHandler(func(rs http.ResponseWriter, rq *http.Request) {
// Handle request as usual. Since it's wrapped in the CommonHandler and we've set some headers there, responses to requests to "/" will contain those headers.
// Be mindful what modifications you're doing here. If, for ex., you decide you want to apply different caching strategy than the Common one, since this will be passed to the CommonHandler, your changes will be overwritten and lost. So it may be a good idea to introduce checks in CommonHandler to determine whether the header exists, before you decide to create it.
}))
serveMux.HandleFunc("/contact", CommonHandler(func(rs http.ResponseWriter, rq *http.Request) {
// handle another request as usual
}))