We're planting a tree for every job application! Click here to learn more

Simple Web Application with Go

Wembley Leach

15 Mar 2019

9 min read

Simple Web Application with Go
  • Go

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:

![Wembley Blog.png](https://functionalworks\-backend\-\-prod.s3.amazonaws.com/logos/45442f06b4b8b901471d77658ae0508e)

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\n", err)
}

}

First, create a [ServeMux](https://golang.org/pkg/net/http# 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](https://golang.org/pkg/net/http# Server). 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.](https://blog.cloudflare.com/exposing-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](https://golang.org/pkg/net/http# Handler) parameter and returns a value of the same type. The function’s body uses the http package’s [http.HandlerFunc](https://golang.org/pkg/net/http# ServeMux.HandleFunc) type to convert functions with signatures that match `http.Handler`'s ServeHttp([ResponseWriter](https://golang.org/pkg/net/http# ResponseWriter), *[Request](https://golang.org/pkg/net/http# 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](https://golang.org/pkg/net/http/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

Go’s templating engine is really powerful, and it comes right out of the box with support for [HTML](https://golang.org/pkg/html/template/) and [text](https://golang.org/pkg/text/template/) 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](https://golang.org/pkg/html/template# Template.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](https://golang.org/pkg/text/template# hdr-Actions) 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 “publicnext 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]( https://github.com/wemgl/simple-server) to see how “publicis 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

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](http://www.gorillatoolkit.org/), [Alice](https://github.com/justinas/alice), and other [Awesome Go](https://awesome-go.com/) 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](https://trackandfitapp.com/) and [https://fitwhittit.com](https://fitwhittit.com/) with these techniques as a foundation, and I hope you’ll be able to do the same.
Did you like this article?

Wembley Leach

See other articles by Wembley

Related jobs

See all

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Title

The company

  • Remote

Related articles

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

JavaScript Functional Style Made Simple

JavaScript Functional Style Made Simple

Daniel Boros

12 Sep 2021

WorksHub

CareersCompaniesSitemapFunctional WorksBlockchain WorksJavaScript WorksAI WorksGolang WorksJava WorksPython WorksRemote Works
hello@works-hub.com

Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ

108 E 16th Street, New York, NY 10003

Subscribe to our newsletter

Join over 111,000 others and get access to exclusive content, job opportunities and more!

© 2024 WorksHub

Privacy PolicyDeveloped by WorksHub