Difference between http.Handle and http.HandleFunc? - go

The Go docs have the following example for the http package:
http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
I'm having sort of a difficulty understanding the difference between Handle and HandleFunc and why two are needed. Can somebody try to explain to a new Gopher in clear words?

Basically, the HTTP server's "mux" has a map of path -> handler interface
Interfaces are used here, I assume, to allow you to implement complex path handlers that have state.
For example the file server from the standard package is a struct that contains the root dir for file service and implements the handler interface.
That said, for simple stuff, a func is easier and more clear. So they added a special generator so you can easily pass in a func.
Take a look at: server.go
from line: 1216 (as of today)
1216 type HandlerFunc func(ResponseWriter, *Request)
1217
1218 // ServeHTTP calls f(w, r).
1219 func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
1220 f(w, r)
1221 }
What they are doing is implementing the interface on a custom type (which happens to match the api of the interface) that just calls itself.

In simple terms:
Problem: I want to create an object (type) that responds to HTTP requests.
Solution: Use http.Handle for that. It accepts an http.Handler as the second argument.
http.Handler is an interface and should implement ServeHTTP from the http package.
Problem: I want a function to respond to my HTTP request.
Solution: Use http.HandleFunc for that. It accepts an http.HandlerFunc as the second argument.
http.HandlerFunc is a function type and should implement ServeHTTP from the http package.

No, it's different. Let's examine:
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
Handle expects us to pass a Handler. Handler is an interface
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
if any type implements ServeHTTP(ResponseWriter, *Request) for example:
myCustomHandler then we can pass it like Handle(pattern string, myCustomHandler).
In the second scenario:
HandleFunc(pattern string, func(w ResponseWriter, r *Request) {
// do some stuff
}
HandleFunc expects a function where Handle expects a Handler interface.
So, if you just want to pass a function then you can use http.HandleFunc(..). Like #David showed that behind the scenes it implements Handler interface by calling ServeHTTP.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}

Handler functions are merely convenient ways of creating handlers.
While both of them can be used to create handlers, but because, using handler functions is cleaner and it does the job just as well, why use handlers at all? It all boils down to design. If you have an existing interface or if you want a type that can also be used as a handler, simply add a ServeHTTP method to that interface and you’ll get a handler that you can assign to a URL. It can also allow you to
build web applications that are more modular.
Using Handle
package main
import (
"fmt"
"net/http"
)
type HelloHandler struct{}
func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
type WorldHandler struct{}
func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "World!")
}
func main() {
hello := HelloHandler{}
world := WorldHandler{}
http.Handle("/hello", &hello)
http.Handle("/world", &world)
http.ListenAndServe(":8080", nil)
}
Using HandleFunc
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
func world(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "World!")
}
func main() {
http.HandleFunc("/hello", hello)
http.HandleFunc("/world", world)
http.ListenAndServe(":8080", nil)
}
Additional information:
http.Handler is an interface with method ServeHTTP(),
// net/http/server.go
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
And here's a ServeHTTP information,
// net/http/server.go
ServeHTTP(w http.ResponseWriter, r *http.Request)
// where,
// http.ResponseWriter is a writer interface, and,
// http.Request is a structure with request details.
Now lets look at HandlerFunc,
// net/http/server.go
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request){
f(w, r)
}
That means, http.HandlerFunc is a type that has ServeHTTP method implemented.
http.HandlerFunc(someFunc)
// where,
// 1. someFunc() must have a signature,
func someFunc(w http.ResponseWriter, r *http.Request)
// 2. That means, http.HandlerFunc(someFunc) is just a type casting of type http.HandlerFunc on a someFunc() and not a function call.
Now lets go to the http.Handle(),
// net/http/server.go
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
By looking at above snippet, you may have noticed that,
2nd argument accepts a Handler interface, that means, you can create any type and implement a ServeHTTP() method for it to satisfy this. Refer below example for proof.
type MyHandler struct{}
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
handler := MyHandler{}
http.Handle("/hello", &handler)
http.ListenAndServe()
}

Related

http.Handler value in argument to r.Handle: missing method ServeHTTP error

I was trying to build basic web API using gorilla mux in Go. Here is my code. Please help me understand how some interfaces are working here.
func main() {
r := mux.NewRouter()
r.Handle("/", http.FileServer(http.Dir("./views/")))
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
r.Handle("/status", myHandler).Methods("GET")
http.ListenAndServe(":8080", r)
}
func myHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
} ```
error :- `cannot use myHandler (value of type func(w http.ResponseWriter, r *http.Request)) as http.Handler value in argument to r.Handle: missing method ServeHTTP `
As the docs for mux.Router.Handle show, it takes a http.Handler. This is an interface with a single method: ServeHTTP(ResponseWriter, *Request).
This is useful if you want to pass an object as a handler.
To register the function myHandler, use mux.Router.HandleFunc instead:
r.HandleFunc("/status", myHandler)
This is also shown in the basic examples of the mux package.

How is HandlerFunc returned by function that should return Handler?

While chaining handlers, the function has a return type of Handler, but it actually returns a HandlerFunc. This does not throw any error.
How is HandlerFunc accepted in place of a Handler, the prior being a function type and the latter being a interface type?
func log(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
...
})
}
The HandlerFunc type is an adapter to allow the use of ordinary
functions as HTTP handlers. If f is a function with the appropriate
signature, HandlerFunc(f) is a Handler that calls f.
The http.Handler is an interface:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
The http.HandlerFunc is a type:
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
http.Handler is an interface. http.HandlerFunc is a concrete type that implements that interface. This is all documented in the http package documentation. If interfaces are new to you, start with A Tour of Go.

panic: Last argument needs to be of type http.HandlerFunc

I have this helper function, which is compiling fine:
func Middleware(adapters ...interface{}) http.HandlerFunc {
log.Info("length of adapters:", len(adapters))
if len(adapters) < 1 {
panic("Adapters need to have length > 0.");
}
h, ok := (adapters[len(adapters)-1]).(http.HandlerFunc)
if ok == false {
panic("Last argument needs to be of type http.HandlerFunc") // ERROR HERE
}
adapters = adapters[:len(adapters)-1]
for _, adapt := range adapters {
h = (adapt.(AdapterFunc))(h)
}
return h
}
I am calling it like so:
router.HandleFunc("/share", h.makeGetMany(v)).Methods("GET")
func (h Handler) makeGetMany(v Injection) http.HandlerFunc {
return mw.Middleware(
mw.Allow("admin"),
func(w http.ResponseWriter, r *http.Request) {
log.Println("now we are sending response.");
json.NewEncoder(w).Encode(v.Share)
},
)
}
the problem is that I am getting this error and I cannot figure out why:
panic: Last argument needs to be of type http.HandlerFunc
goroutine 1 [running]:
huru/mw.Middleware(0xc420083d40, 0x2, 0x2, 0xc42011f3c0)
/home/oleg/codes/huru/api/src/huru/mw/middleware.go:301 +0x187
huru/routes/share.Handler.makeGetMany(0xc4200ae1e0, 0x10)
/home/oleg/codes/huru/api/src/huru/routes/share/share.go:62 +0x108
it does confirm that the length of the adapters slice is 2:
length of adapters:2
anyone know why that type assertion would fail in this case? Makes no sense. Maybe I am not actually retrieving the last argument of the slice or something? Is there a better way to pop the last argument off the slice?
You need to wrap the 2nd argument of mw.Middleware() statement into http.Handler type by using http.HandlerFunc().
func (h Handler) makeGetMany(v Injection) http.HandlerFunc {
return mw.Middleware(
mw.Allow("admin"),
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("now we are sending response.");
json.NewEncoder(w).Encode(v.Share)
}),
)
}
In the http package,
ListenAndServe has the following signiture
func ListenAndServe(addr string, handler Handler) error
where the Handler (i.e., http.Handler) is an interface
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
For one web application, there is only one ListenAndServe call, thus only onehandler, which needs to deal with all the access points such as /url1, /url2, etc. If we write the handler from scratch, the implementation could be a custom struct that wraps around a database handle. Its ServeHTTP method checks the access point, and writes the corresponding content to the ResponseWriter, which is quite tedious and mingled.
That's the motivation of ServeMux, which is the router in your code. It has a ServeHTTP method so it satisfies the http.Handler interface and can be used for ListenAndServe. In addition, it has the HandleFunc method to deal with the individual access point
func (mux *ServeMux) HandleFunc(pattern string,
handler func(ResponseWriter, *Request))
Note here the handler is not a http.Handler, i.e., it doesn't have ServeHTTP method. It doesn't have to because the mux already has ServeHTTP and its ServeHTTP method can dispatch the individual access point request to the corresponding handlers.
Note it also has a Handle method, which requires the argument to satisfy the http.Handler interface. It's slightly less convenient to use compared to the HandleFunc method.
func (mux *ServeMux) Handle(pattern string, handler Handler)
Now back to your question, since you call router.HandleFunc, its input doesn't have to be http.Handler. So an alternative solution is to use func(ResponseWriter, *Request) as the return type for your middleware and makeGetMany method. (the type assertion in the middleware also needs to be updated, probably a lot more code needs to be updated as well)
#xpare's solution is to do type conversion so that all the function signatures match up, i.e., convert func(ResponseWriter, *Request) to http.HandlerFunc. It is also interesting to see how it works. From the implementation
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
you can see that it basically defines a ServeHTTP method to call itself.

Where does the serveHTTP utility come from on supposedly naked func

I have this utility:
type Handler struct{}
func (h Handler) Mount(router *mux.Router, v PeopleInjection) {
router.HandleFunc("/api/v1/people", h.makeGetMany(v)).Methods("GET")
}
the above calls this:
func (h Handler) makeGetMany(v PeopleInjection) http.HandlerFunc {
type RespBody struct {}
type ReqBody struct {
Handle string
}
return tc.ExtractType(
tc.TypeList{ReqBody{},RespBody{}},
func(w http.ResponseWriter, r *http.Request) {
// ...
})
}
and then tc.ExtractType is like so:
func ExtractType(s TypeList, h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(w, r) // <<< h is just a func right? so where does ServeHTTP come from?
}
}
my question is - where does the serveHTTP method/func come from??
isn't the h parameter just a func with this signature:
func(w http.ResponseWriter, r *http.Request) { ... }
so then how does that func have the ServeHTTP func attached to it?
In other words, why I am I calling
h.ServeHTTP(w,r)
instead of
h(w,r)
?
The http.HandlerFunc is a type represent func(ResponseWriter, *Request).
The difference between http.HandlerFunc and func(ResponseWriter, *Request) is: http.HandlerFunc type has method called ServeHTTP().
From the source code:
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
The http.HandlerFunc() can be used to wrap handler function.
func Something(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do something
next.ServeHTTP(w, r)
})
}
The wrapped handler will have http.HandlerFunc() type, meaning we'll be able to access it's .ServeHTTP() method.
There is also another type, an interface called http.Handler. It has .ServeHTTP() method signature, and it must be implemented on the struct where the interface is being embedded.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
As you can see on Something() function above, a return value in http.Handler type is required, but we returned a handler wrapped in http.HandlerFunc(). It's fine, because the http.HandlerFunc has method .ServeHTTP() who fulfil the requirement of http.Handler interface.
In other words, why I am I calling h.ServeHTTP(w,r) instead of h(w,r)?
Because to continue serve the incoming request, you need to call .ServeHTTP().

How to implement HandlerFunc without using DefaultServeMux

If I were to use the DefaultServeMux (which I designate by passing nil as the second argument to ListenAndServe), then I have access to http.HandleFunc, which you see used below in this example from the Go wiki:
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
In my current code, I am not able to use the DefaultServeMux i.e. I'm passing a custom handler to ListenAndServe
h := &mypackage.Handler{
Database: mydb
}
http.ListenAndServe(":8080", h)
so I don't get the http.HandleFunc built in. However, I have to adapt some authorization code to my code base that requires something like http.HandleFunc. For example, if I had been using DefaultServeMux, when I hit the "/protected" route, I would want to go to the Protected handler, but only after passing through the h.AuthorizationHandlerFunc like this
h.AuthorizationHandlerFunc(Protected)
However, since I'm not using DefaultServeMux, it's not working i.e. I'm not able to pass the Protected function (and have it called) to the AuthorizationHandlerFunc. This is the implementation of the AuthorizationHandlerFunc below. You can see below that Protected never gets called.
Question: how do I implement HandlerFunc in this situation (without using DefaultServeMux)?
func (h *Handler) AuthorizationHandlerFunc(next http.HandlerFunc) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
h.AuthorizationMiddleWare(w, r, next)
})
}
func (h *Handler) AuthorizationMiddleWare(w http.ResponseWriter, r *http.Request, next http.HandlerFunc){
//other stuff happens
log.Println("this is never getting called")
next(w,r)
}
func (h *Handler)Protected(w http.ResponseWriter, r *http.Request){
log.Println("this is never getting called")
}
Update
ServeHTTP is implemented on mypackage.Handler. Why is the Protected function not getting called, or, for that matter, the relevant code in the AuthorizationMiddleWare?
Re-implement your authorization middleware as a http.Handler :
type auth struct {
DB *sql.DB
UnauthorizedHandler http.Handler
}
func NewAuth(db *sql.DB, unauthorized http.Handler) *auth {
return auth{db, unauthorized}
}
func (a *auth) Protected(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// Check whether the request is valid
// If it's invalid, call your error func and make sure to *return* early!
if !valid {
a.UnauthorizedHandler.ServeHTTP(w, r)
return
}
// Call the next handler on success
h.ServeHTTP(w, r)
return
}
return http.HandlerFunc(fn)
}
func someHandler(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello!\n")
}
func main() {
auth := NewAuth(db, errorHandler)
r := http.NewServeMux()
// We have a http.Handler implementation that wraps a http.HandlerFunc
// ... so we call r.Handle on our ServeMux and type-cast the wrapped func
r.Handle("/protected", auth.Protected(http.HandlerFunc(someHandler)))
// Just a simple http.HandlerFunc here
r.HandleFunc("/public", someOtherHandler)
log.Fatal(http.ListenAndServe(":8000", r))
}
Take a look at the httpauth lib I wrote for a different example with a ServeHTTP method. Both the above and explicitly creating a ServeHTTP method on your type are valid approaches.

Resources