Minimal Server

Getting Started

Let’s start by making a minimal web server in a single executable (main) Go package and running it. We’ll use the standard library’s net/http package to create a Server and register Handlers for returning simple HTTP responses.

Create a directory github.com/username/gopherpad inside your $GOPATH/src. This will serve as the Gopherpad project directory and as the Go main package implementing the initial website.

The net/http package exposes a Server struct which has fields Addr and Handler (among others) and can start listening for incoming requests over TCP when server.ListenAndServe() is invoked. An Addr is a string representing a TCP network address and a Handler is any object that has a ServeHTTP(ResponseWriter, *Request) method to implicitly satisfy the Handler interface.

Create an app.go file to start a Server with a single Handler.

package main

import (
    "fmt"
    "net/http"
)

// main starts serving the web application
func main() {
    srv := &http.Server{
        Addr:    "localhost:8080",
        Handler: helloHandler{},
    }
    srv.ListenAndServe()
}

// helloHandler writes a greeting
type helloHandler struct{}

func (h helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World")
}

Since the source code is in a single file, you can use ‘go run’ to compile the file to a temporary directory and run it:

$ cd gopherpad
$ go run app.go

A more typical approach is to install the executable and run it. An executable package builds an executable command with the name of the package directory (i.e. gopherpad).

$ cd gopherpad
$ go install .
$ gopherpad      // $GOPATH/bin should be on your PATH

Open localhost:8080 to check the ‘Hello World’ result. Ctrl+C to stop the process.

Notice that with a single Handler, every path (e.g. /foo, /bar) routes to the same Handler. We’ll address that limitation with a ServeMux.

URL Routing: ServeMux

The net/http package exports ServeMux, a simple HTTP request multiplexer to support URL routing. ServeMux allows pattern, Handler pairs to be registered. It implements ServeHTTP(ResponseWriter, *Request) by matching a request URL against the closest registered pattern string and calling through to the corresponding Handler. This makes a ServeMux a type of Handler our Server can use.

net/http provides a global DefaultServeMux instance for convenience. URL patterns and Handlers can be registered on it via http.Handle(pattern string, handler Handler) or http.HandleFunc(pattern string, handler func(ResponseWriter, *Request)). The later option allows the handler to be a function, which eliminates the need for the empty struct used previously.

Update app.go:

package main

import (
    "fmt"
    "log"
    "net/http"
)

// init registers patterns and handlers on DefaultServeMux
func init() {
    http.HandleFunc("/", helloHandler)
    http.HandleFunc("/notes", noteHandler)
}

// main starts serving the web application
func main() {
    address := "localhost:8080"
    log.Printf("Starting Server listening on %s\n", address)
    // create and start Server with DefaultServeMux Handler
    err := http.ListenAndServe(address, nil)
    if err != nil {
        log.Fatal("ListenAndServe error: ", err)
    }
}

// helloHandler writes a greeting
func helloHandler(writer http.ResponseWriter, request *http.Request) {
    fmt.Fprintf(writer, "Hello World")
}

// noteHandler writes a HTML textarea
func noteHandler(writer http.ResponseWriter, request *http.Request) {
    fmt.Fprintf(writer, "<h1>Gopherpad</h1><textarea></textarea>")
}

Note

The standard library’s ServeMux accepts simple, fixed URL patterns. When variable parts in URL patterns are needed, in Pattern Routing, we’ll see how to easily swap in a different multiplexing handler for that purpose.

This registers the pattern “/notes” to the noteHandler function and the default pattern “/” to the helloHandler (which is now a function instead of a struct) onto the global http.DefaultServeMux. Each Go source file can have an init function to initialize declarations and state as is used here.

The executable’s main function has changed to use the net/http library’s http.ListenAndServe(addr string, handler Handler) utility function which creates a Server with the given Address and Handler and starts it listening for incoming requests. Passing a nil Handler argument, indicates that the http.DefaultServeMux should be used as the Handler.

Re-run the server and localhost:8080/notes will show a simple HTML textarea, while other paths show the default “Hello World” message as before.

$ cd gopherpad
$ go install .
$ gopherpad
2014/11/27 16:38:57 Starting Server listening on localhost:8080
_images/hardcoded-new-note.png

Each HTML response is hardcoded in a handler, a limitation that will be addressed with Templates later.