Web application development is more popular now than it has ever been before. The tools have advanced so much that some people can get by with their Google Pixelbook alone, but that level of advancement often scares beginners off — not only because the apps they see look complex, but also because getting a local development environment set up is a daunting task.

Take for example setting up a ReactJS, Spring Boot, or Ruby on Rails environment. They all require some additional tool like npx (or npm or yarn), maven (or gradle), or the rails CLI tool to be setup and configured before writing a single line of code. Now, that’s no big deal once you’re familiar enough with the tooling and already have everything installed, but for a beginner that’s a huge barrier to entry.

This where Go comes in. With Go, all someone needs is to install the binary for their operating system, a few commands to setup the project, knowledge of HTTP, HTML, CSS, and JavaScript, and they’re ready to go (haha). Its standard library includes a really powerful templating engine, HTTP server, and testing package to get started right away. This post will demonstrate how easy it is to build the foundation for a web application that includes most of what’s needed for any web application, besides the database integration stuff, because for that you can see my other post about How to Use the Official MongoDB Go Driver for an example of using MongoDB with Go. So, let’s get started!

Environment Setup

Navigate to any directory on your machine using Terminal, PowerShell, or command prompt, once you have Go installed, and create a new directory called simple-server. That process might look like this:

$ mkdir simple-server $ cd simple-server $ go mod init github.com/wemgl/simple-server

This will create a module enabled Go project, the contents of which look like this for Go v1.12:

module github.com/wemgl/simple-server go 1.12

Writing the Code

Now, with all that environment setup out of the way, let’s start writing some code. What we’re going to build is really simple, and it looks like this:

We’ll begin by implementing the main function. It’s responsible for creating the server and registering the handlers (i.e. routes) that will receive HTTP requests and return responses to clients. This main function is a good starting point for building your web applications with Go:

func main() { mux := http.NewServeMux() mux.Handle("/public/", logging(public())) mux.Handle("/", logging(index())) port, ok := os.LookupEnv("PORT") if !ok { port = "8080" } addr := fmt.Sprintf(":%s", port) server := http.Server{ Addr: addr, Handler: mux, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 15 * time.Second, } log.Println("main: running simple server on port", port) if err := server.ListenAndServe(); err != nil { log.Fatalf("main: couldn't start simple server: %v

", err) } }

First, create a ServeMux that the server will use to match request URLs to patterns and handlers; second, attach specific patterns and their handlers to the ServeMux — patterns for the index page and for serving static files are attached in this example; and third, create the web Server and start it up. You’ll notice that the server type Go provides can be customized. Here, we specify some timeouts, but we could also have added HTTPS support if we wanted to be more secure about how we expose Go on the internet.

Request Routing

Middleware So, you’ve probably already noticed the Handle function on the ServeMux type. Let’s look at the logging and index handlers that are added to see what’s happening in more detail. First, here’s the logging middleware:

// logging is middleware for wrapping any handler we want to track response // times for and to see what resources are requested. func logging(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() req := fmt.Sprintf("%s %s", r.Method, r.URL) log.Println(req) next.ServeHTTP(w, r) log.Println(req, "completed in", time.Now().Sub(start)) }) }

It’s a simple method and demonstrates how middleware functions—used for pre-processing requests before they get to the actual handler that performs some action based on the HTTP verb in the request — are written in Go. In the example we create a function that takes a http.Handler parameter and returns a value of the same type. The function’s body uses the http package’s http.HandlerFunc type to convert functions with signatures that match http.Handler 's ServeHttp(ResponseWriter, *Request) method into http.Handler s the server can use. That way we can chain handlers and add as many middleware we we’d like before our main handler method. In this example we simply time how long the request takes and print out the associated URL, but you can create middleware like this to perform just about any action you could think of (e.g. ensuring a user is authenticated, that a JWT token hasn’t expired yet, etc.).

A majority of the information you’ll need to properly handle requests by HTTP verb, make decisions based on the URL, and access HTTP headers, are all in the documentation of the http.Request type, so look there first whenever there’s something you’re not 100% sure how to do.

Index Handler Let’s take a look at the index handler now to understanding how content is usually rendered in Go web applications:

// templates references the specified templates and caches the parsed results // to help speed up response times. var templates = template.Must(template.ParseFiles("./templates/base.html", "./templates/body.html")) // index is the handler responsible for rending the index page for the site. func index() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { b := struct { Title template.HTML BusinessName string Slogan string }{ Title: template.HTML("Business | Landing"), BusinessName: "Business,", Slogan: "we get things done.", } err := templates.ExecuteTemplate(w, "base", &b) if err != nil { http.Error(w, fmt.Sprintf("index: couldn't parse template: %v", err), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) }) }

As you can see, this function returns a http.Handler too, which we create similarly to the one returned by the logging middleware. This handler is responsible for rendering the site’s index page, which it does by executing a cached template named “base”, and populating the result with values we specified in an instance of an anonymous struct type. We then set the response status header and return. We don’t have to explicitly set the 200 OK status here because Go does that by default, but it demonstrates how to set status headers.

In a more complex handler, it’s important to be able to verify that it’s functioning as expected. This is usually done with one or more unit tests that verify things like the request response is correct, there’s a valid body, content is properly persisted to the database, etc. So, here’s an example of how we can do that in Go for this simple index handler:

func TestIndex(t *testing.T) { req, err := http.NewRequest(http.MethodGet, "/", nil) if err != nil { t.Fatalf("TestIndex: couldn't create HTTP GET request: %v", err) } rec := httptest.NewRecorder() index().ServeHTTP(rec, req) res := rec.Result() defer func() { err := res.Body.Close() if err != nil { t.Fatalf("TestIndex: couldn't close response body: %v", err) } }() if res.StatusCode != http.StatusOK { t.Errorf("TestIndex: got status code %v, but want: %v", res.StatusCode, http.StatusOK) } body, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatalf("TestIndex: could not read response body: %v", err) } if len(string(body)) == 0 { t.Errorf("TestIndex: unexpected empty response body") } }

This code is stored in a file, called main_test.go , in the same directory as the server’s main.go file. It can be run from the command-line with:

$ go test

Go automatically detects any files named *_test.go and executes them. Also, Go’s testing and httptest packages come with useful types and functions, that work in conjunction with those of the http package, for exercising web servers and their handlers. In this testing example, we create a request for the index page, create a http.ResponseRecorder to capture the request’s response so we can use it later on in the test, make the request to the index handler by calling its ServeHTTP method, and then finally, asserting the status code and body are good. When all tests are passing the terminal output will look something like this:

Wembleys-MacBook-Pro:simple-server wembleyleach$ go test PASS ok github.com/wemgl/simple-server 0.073s

Templating

Go’s templating engine is really powerful, and it comes right out of the box with support for HTML and text templating. In this simple web application, we take advantage of the HTML templating support to ensure all templated content is safe against code injection. The templates, stored in a directory called “templates,” that lives right next to our main.go file, look like this:

{{define "base"}} <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="shortcut icon" type="image/x-icon" href="/public/assets/images/favicon.ico"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Work+Sans:400,500,600,700"> <link rel="stylesheet" type="text/css" href="/public/assets/styles/style.css"> <title>{{.Title}}</title> </head> <body> {{template "body" .}} </body> </html> {{end}}

{{define "body"}} <h1 class="hidden">Simple Server Body</h1> <header class="header"> <h1 class="hidden">Header</h1> <img class="logo" src="/public/assets/images/logo.svg"> <nav class="navigation"> <h2 class="hidden">Navigation</h2> <ul class="navigation__items"> <li class="navigation__item">Home</li> <li class="navigation__item">About</li> <li class="navigation__item">Contact</li> </ul> </nav> </header> <main> <h1 class="hidden">Main Content</h1> <article class="hero"> <h2 class="hidden">Main Article</h2> <section class="hero__text"> <h3 class="hidden">Main section</h3> <p class="salutation salutation--bg"> <span class="salutation__greeting">{{.BusinessName}}</span> <span class="salutation__message">{{.Slogan}}</span> </p> <div class="js-container"></div> </section> </article> </main> <script type="text/javascript" src="/public/assets/scripts/main.js"></script> {{end}}

Although these features aren’t shown, Go’s template package supports constructs for conditional logic, iteration over slices and arrays, and even adding custom functions for non-standard behaviors. When we call templates.ExecuteTemplate we pass arguments for where the result of the execution will be written, the name of the template, and a data object that contains values for each Action in the template. In this example we render the template “base,” because that’s the top level template that includes the dynamic “body” template.

Serving Static Content

At this point we have handlers for responding to client requests and templates for displaying content, so what’s next? Well, if you look at the templates again, you’ll see a few link and script tags for some additional static files containing CSS styling and JavaScript scripts. Go has a built in http.FileServer handler for serving this type of content. Adding it to the server is similar to how we added the index handler and logging middleware — by declaring a function that returns a http.Handler :

// public serves static assets such as CSS and JavaScript to clients. func public() http.Handler { return http.StripPrefix("/public/", http.FileServer(http.Dir("./public"))) }

Now, by creating a directory called “public” next to the main.go file, and placing all static content in there, our templates will be able to properly request all styles and scripts needed to function properly. You can find the static files for this simple web application at this GitHub repo to see how “public” is structured. At this point, if you run:

$ go run main.go

and open http://localhost:8080/ in your browser, you’ll see something like this in the terminal:

$ go run main.go 2019/03/10 11:15:41 main: running simple server on port 8080 2019/03/10 11:15:47 GET / 2019/03/10 11:15:47 http: superfluous response.WriteHeader call from main.index.func1 (main.go:47) 2019/03/10 11:15:47 GET / completed in 649.039µs 2019/03/10 11:15:47 GET /public/assets/images/favicon.ico 2019/03/10 11:15:47 GET /public/assets/images/favicon.ico completed in 14.892991ms

Conclusion

That’s it! A simple web application written in Go. Hopefully you can see that creating a simple web application using Go isn’t as difficult as it could be if you chose some of the other languages and frameworks that are out there. It’s possible to configure a secure and fast web server, add templates, serve static content, and test your application using just the standard library.

But, if the standard library ever isn’t enough, there are tools like the Gorilla Toolkit, Alice, and other Awesome Go packages out there that integrate nicely with it so you can plug in whatever you need. I’ve been able to launch sites like https://trackandfitapp.com and https://fitwhittit.com with these techniques as a foundation, and I hope you’ll be able to do the same.