I would like to make a function that can be a HandleFunc for http
but also be called with another writer.
Since http.ResponseWriter
implements io.Writer
and my function does not need to set HTTP headers, I thought it might be possible:
func doit(w io.Writer, r *http.Request) {
w.Write([]byte("Hello"))
}
http.HandleFunc("/", doit)
But no:
cannot use doit (type func(io.Writer, *http.Request)) as type func(http.ResponseWriter, *http.Request) in argument to http.HandleFunc
That makes sense, because it would require a type assertion to make an io.Writer compatible with an expected http.ResponseWriter.
Is something like that possible with functions?
A function type denotes the set of all functions with the same parameter and result types.
Your doit()
function does not qualify to be an http.HandlerFunc
because parameter types do not match. The types io.Writer
and http.ResponseWriter
are 2 completely different types, so the function types taking these types are also different.
However, since the method set of the interface type io.Writer
is a subset of the method set of http.ResponseWriter
, a value of the latter type can be assigned to the variable of the former type.
You may wrap it in an anonymous function of type http.HandlerFunc
which may simply call doit()
, and then you may use it as an http.HandlerFunc
:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
doit(w, r)
})
If you need this many times, you may create a helper function to produce the http.HandlerFunc
function value:
func wrap(f func(w io.Writer, r *http.Request)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
f(w, r)
}
}
And then using it is simply:
http.HandleFunc("/", wrap(doit))
Handler
typeAnother option would be to define your own function type, to which you can attach a simple method to implement http.Handler
(namely ServeHTTP()
), and that way with a simple type conversion you can register your function as a handler:
type SimpleHandler func(io.Writer, *http.Request)
func (sh SimpleHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
sh(w, r)
}
Using it:
http.Handle("/", SimpleHandler(doit))
Note that the expression SimpleHandler(doit)
is simply a type conversion, it's not a function call. So there are no new values or anonymous functions created here in the background, this solution is the most efficient.