I am learning Go and at the moment trying to understand what and how actually julienschmidt's httprouterhttp router works. Especially how the router.HandlerFunc() works.
Go's http package:
http.Handler
: Handler is an Interface. Any type which has the same method signature i.e., ServeHTTP(w,r) implements a Handler.http.Handle
: http.Handle is a function which has two parameters. 1) String to match request path, 2)Handler, to call its ServeHTTP() method.http.HandlerFunc
: A custom function type with function signature (ResponseWriter, *Request) and its own ServeHTTP(w,r) method, which satisfies as a http.Handler interface.
Now if I need to use a function eg. Bar(ResponseWriter, *Request) which satisfies to be a HandlerFunc, inside http.Handle, I type caste/covert the function to http.HandlerFunc and then use it inside the http.Handle. Like so:
func Bar(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("My bar func response"))
}
...
mf := http.HandlerFunc(Bar)
http.Handle("/path", mf)
- Looking at the http.HandleFunc source code, this is how http.HandleFunc() works. It expects a function which as the signature of (w ResponseWriter, r *Request) and type caste the function.
Like so:
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
julienschmidt's httprouterhttp
Looking at the source code of router.HandlerFunc()
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
r.Handler(method, path, handler)
}
- Instead of expecting a function with appropriate signature (ResponseWriter, *Request) like the http.HandleFunc(), it expects a http.HandlerFunc.
- Also without type casting/converting the function to a HandlerFunc type, it just pass the function to another function router.Handler(method, path string, handler http.Handler), which again expects a Handler.
So I can execute this code without any problem:
router.HandlerFunc(http.MethodPost, "/path", Bar) // Bar is not type casted/converted to a HandlerFunc
I can understand type casting the Bar to a HandlerFunc and then pass it to router.HandlerFunc().
Could you please clear some of my doubts:
- How does without type casting the Bar() to a HandlerFunc satisfies as a HandlerFunc type to the router.HandlerFunc()?
- If the router.Handler() expects a http.Handler type, how come Bar() without type casting to the http.HandlerFunc satisfies a a Handler to the router.Handler()?
- What am I missing?
CodePudding user response:
- "How does without type casting the Bar() to a HandlerFunc satisfies as a HandlerFunc type to the router.HandlerFunc()?"
The expression
router.HandlerFunc(http.MethodPost, "/path", Bar)
complies with the rules of Assignability:
V
andT
have identical underlying types and at least one ofV
orT
is not a named type.
The Bar
function's type and the http.HandlerFunc
type have identical underlying types, and Bar
's type is not named. Because of that you can pass (assign) Bar
as the handler
argument to httprouter.Router.HandlerFunc
without an explicit conversion.
- "If the router.Handler() expects a http.Handler type, how come Bar() without type casting to the http.HandlerFunc satisfies a a Handler to the router.Handler()?"
In the following method definition
func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) {
r.Handler(method, path, handler)
}
there is no Bar
, there's only the handler
argument whose type is http.HandlerFunc
and that type does implement the http.Handler
interface. So the statement r.Handler(method, path, handler)
is perfectly legitimate.
- "What am I missing?"
See above.
CodePudding user response:
Look at definition of HandlerFunc
type HandlerFunc func(ResponseWriter, *Request)
And the signature of your function
(w http.ResponseWriter, r *http.Request)
You don't need conversion here.