DEV Community

Cover image for Reading Code of Golang HTTP Server
Kenta Takeuchi
Kenta Takeuchi

Posted on • Originally published at bmf-tech.com

Reading Code of Golang HTTP Server

This article was originally published on bmf-tech.com.

Overview

I took notes while reading the internal code of an HTTP server when I created a router in Go.

github.com - bmf-san/goblin

Reading Code of HTTP Server

Basic Form

This is the typical code structure you would see when you start learning Go.

Various elements have been omitted to arrive at this form.

package main

import (
    "net/http"
)

func main() {
    http.HandlerFunc("/index", func(w http.ReponseWriter, req *http.Request) {
        w.Write([]byte("hello world"))
    })

    http.ListenAndServe(":8080")
}
Enter fullscreen mode Exit fullscreen mode

Detailed Form Without Omissions

This is the previous basic form written out in detail without omissions. Let's confirm step by step how the implementation leads to the basic form.

package main

import (
    "net/http"
)

func main() {
    // Multiplexer. A structure for URL matching. Only resolves static routing.
    mux := http.NewServeMux()
    ih := new(indexHandler)
    // Register routing to mux
    mux.Handle("/index", ih)

    srv := http.Server{
        Addr: ":8080",
        Handler: mux,
    }

    srv.ListenAndServe()
}

// Structure that implements the Handler interface.
type indexHandler struct{}

// Implement ServeHTTP
func (i *indexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("helo world"))
}
Enter fullscreen mode Exit fullscreen mode

Replacing Handler

First, let's replace the Handler.

ServeHTTP can be replaced with the function type alias HandlerFunc.

cf.

package main

import (
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    // Just cast a regular function to HandlerFunc type. It satisfies the Handler interface.
    mux.Handle("/index", http.HandlerFunc(indexHandler))

    s := http.Server{
        Addr: ":8080",
        Handler: m,
    }
    s.ListenAndServe()
}

// No need to implement ServeHTTP with an arbitrary structure.
func indexHandler(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("hello world"))
}
Enter fullscreen mode Exit fullscreen mode

Using DefaultServeMux

You can substitute mux with DefaultServeMux.

DefaultServeMux has a structure of type ServeMux.

It implements a function to register routing to the mux called HandlerFunc.

cf.

package main

import (
    "net/http"
)

func main() {
    // No need to create mux, this is enough
    http.HandleFunc("/index", indexHandler)

    s := http.Server{
        Addr: ":3000",
        // The variable that net/http has by default. DefaultServeMux has a structure of type ServeMux. It implements a function to register routing to the mux called HandlerFunc.
        Handler: http.DefaultServeMux,
    }
    s.ListenAndServe()
}

func indexHandler(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("hello world"))
}
Enter fullscreen mode Exit fullscreen mode

Using ListenAndServe()

You can also use ListenAndServe() without creating a Server structure (http.Server{}).

cf.

package main

import (
    "net/http"
)

func main() {
    http.HandlerFunc("/index", func(w http.ReponseWriter, req *http.Request) {
        w.Write([]byte("hello world"))
    })

    // No need to create a Server structure (http.Server{})
    http.ListenAndServe(":8080")
}
Enter fullscreen mode Exit fullscreen mode

This brings us back to the initial basic form.

Conclusion

When creating an API server, you might not think about this often, but knowing it can be helpful when you want to extend something.

When creating a router, you should be aware of the http.Handler interface and create a mux accordingly.

Original Source

Go Router Custom Implementation Discussion

Top comments (0)