In the example below I've embedded http.ResponseWriter
into my own struct called Response
. I've also added an extra field called Status
. Why can't I access that field from inside my root
handler function?
When I print out the type of w
in my root handler function it says it's of type main.Response
which seems correct and when I print out the values of the struct I can see that Status
is there. Why can't I access by going w.Status
?
This is the contents of stdout:
main.Response
{ResponseWriter:0xc2080440a0 Status:0}
Code:
package main
import (
"fmt"
"reflect"
"net/http"
)
type Response struct {
http.ResponseWriter
Status int
}
func (r Response) WriteHeader(n int) {
r.Status = n
r.ResponseWriter.WriteHeader(n)
}
func middleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := Response{ResponseWriter: w}
h.ServeHTTP(resp, r)
})
}
func root(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("root"))
fmt.Println(reflect.TypeOf(w))
fmt.Printf("%+v\n", w)
fmt.Println(w.Status) // <--- This causes an error.
}
func main() {
http.Handle("/", middleware(http.HandlerFunc(root)))
http.ListenAndServe(":8000", nil)
}
w
is a variable of type http.ResponseWriter
. ResponseWriter
does not have a field or method Status
, only your Response
type.
http.ResponseWriter
is an interface type, and since your Response
type implements it (because it embeds ResponseWriter
), the w
variable may hold a value of dynamic type Response
(and in your case it does).
But to access the Response.Status
field, you have to convert it to a value of type Response
. For that use Type assertion:
if resp, ok := w.(Response); ok {
// resp is of type Response, you can access its Status field
fmt.Println(resp.Status) // <--- properly prints status
}