Welcome back to the fifth instalment of our in-depth exploration of creating dynamic web servers using Golang! In this post, we’re diving into the fascinating world of HandlerFunc. As you’ve come to expect, GoLang provides us with an elegant and powerful way to handle requests through this mechanism. Let’s embark on this journey of discovery.

Check out previous posts:

Part 1: https://surajincloud.com/understanding-http-server-in-go-basic

Part 2: https://surajincloud.com/understanding-http-server-in-go-using-httpserver-struct

Part 3: https://surajincloud.com/understanding-http-server-in-go-handlers

Part 4: https://surajincloud.com/understanding-http-server-in-go-multiple-handlers

Let’s dive into the code to uncover the magic behind HandleFunc:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

| You can find the code here: https://pkg.go.dev/net/http#HandleFunc

As you can see, HandleFunc takes in a URL pattern and a handler function. It then registers this handler function with the DefaultServeMux, allowing it to be invoked when the corresponding URL is accessed.

Taking it a step further, let’s peek into the HandleFunc method itself:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}

| You can find the code here: https://pkg.go.dev/net/http#ServeMux.HandleFunc

Here, HandleFunc within a custom ServeMux instance ensures that the provided handler function is not nil. Once validated, it invokes the underlying Handle method, associating the pattern with an HandlerFunc instance that wraps the provided handler function.

Let’s understand this with the help of example,

package main

import (
    "fmt"
    "net/http"
)

func Handler1(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World - 1")
}

func main() {
    s := http.Server{
        Addr: ":8080",
    }

    http.HandleFunc("/hello1", Handler1)

    s.ListenAndServe()
}

In this example, we define a Handler1 function that writes “Hello World - 1” to the response writer. We then use http.HandleFunc to associate this handler with the /test URL path.

Let’s test the code,

$ curl localhost:8080/hello1
Hello World - 1

We can now assign multiple handlers to paths quite easily.

package main

import (
    "fmt"
    "net/http"
)

func Handler1(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World - 1")
}

func Handler2(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World - 2")
}

func main() {
    s := http.Server{
        Addr: ":8080",
    }

    http.HandleFunc("/hello1", Handler1)
    http.HandleFunc("/hello2", Handler2)

    s.ListenAndServe()
}

With HandlerFunc, handling multiple routes becomes a breeze. By leveraging the power of this mechanism, you can create cleaner, more organized, and easily maintainable code.

Stay tuned for the next part of our journey, where we’ll unravel the intricacies of dynamic routing using http.ServeMux. The world of GoLang web servers is evolving before our eyes, and we’re equipping you with the knowledge to master it.

Happy coding!