Go is an open source programming language developed at Google and designed to help build simple reliable software systems. The core strength of Go is its concurrency mechanisms which make it simpler to write software, to exploit multi-core architectures.
It's a compiled, strongly - statically typed, concurrent and garbage-collected language.
It's a very interesting, modern day language because of some of the choices that have been made during its design. For example, the Type System, although Go has methods and also an OO style of programming, there is no type hierarchy. The only way to achieve that is through interfaces.
How Go Differs From Others
One should read the language specification to get a better understanding of the design elements of the language. It is really concise and helps bring out some really interesting details. The way Go differs from other typical programming languages, is that it has features unlike other OO languages:
- No Type Inheritance
- No overloading of methods and operators
- Built in concurrency primitives, which make it really stand out from the crowd. It shares memory by communicating and not the other way round.
- A toolchain that uses a traditional model of compile and link to generate binaries without external dependencies.
- Maps are built in.
Code Organization
The Go code is kept under workspaces. It's just a directory hierarchy, as follows:
-
src
- contains Go source files as packages -
pkg
- contains package objects -
bin
- contains executables
The Go tool builds the source packages and installs the resulting binaries in bin
and pkg
directories.
A Simple Web Application Using Go
Let's build a static site and then go on to improve it so that it behaves much more dynamically, based on user input.
The Static Site
The code structure for the static site looks like so:
So, essentially you would want to create a structure similar to the above image or as is showed in the repository. This repo structure would itself reside under the workspace
. Read about the Go Code Structure for more information.
Now what we want to do is serve an HTML file residing in the public directory.
The index.html
contents are as follows:
<!DOCTYPE html> <html> <head> <title>Static site using Go</title> <link rel="stylesheet" type="text/css" href="stylesheets/gostatic.css"> </head> <body> <h1>Developing Website using Go</h1> <p>I am a static page, being served to you with the help of Go lang.</p> </body> </html>
And here's the Go program to serve files statically from the public folder:
package main import ( "net/http" ) func main() { fs := http.FileServer(http.Dir("public")) http.ListenAndServe(":8080", fs) }
Allow me to explain:
- net/http - this package provides HTTP client and server implementations.
- FileServer - this function returns a handler that serves HTTP requests with the contents of the file system.
That's it. Really simple and to the point. You can run the code using the following: go run gostatic.go
.
A Better Solution
However, this solution does not clearly separate the routing and serving concerns and hence, a better solution would be along the lines of:
package main import ( "net/http" "log" ) func main() { fs := http.FileServer(http.Dir("public")) http.Handle("/", fs) log.Println("Listening...") err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
ListenAndServe
starts an HTTP server on the given TCP address and then calls Serve with a handler. This handler is typically nil, so that the default router (in Go’s case the DefaultServerMux can take over).
Now in regards to DefaultServeMux - Let's take a short detour to understand how Go does HTTP processing. It does so with the help of two primary things.
- ServerMuxes - (Router) Its a multiplexer - essentially a HTTP router, which compares incoming requests against the defined list and then calls the associated handler.
- Handlers - These are responsible for 'handling' the request, like responding with the appropriate headers, body etc. Any object obeying the Handler interface can act as one.
Go ahead and run the sample web app as done earlier and you should see the output!
Dynamic Sites - Adding a Timestamp on Every Refresh
Next, let's write the application so that it prints the current time, implying that on every refresh you get a different output. The Go code would look like so:
package main import ( "fmt" "net/http" "time" ) func main() { http.HandleFunc("/", handler) log.Println("listening...") err := http.ListenAndServe(":8080", nil) if err != nil { panic(err) } } func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello. The time is : " + time.Now().Format(time.RFC850)) }
Here we have imported fmt
to work with some printing functions. The fmt implements formatted I/O functions along the lines of C's stdio
library.
We have also made use of HandleFunc
which registers the URL path with the handler function in the DefaultServeMux. The function handler is of the type http.HandlerFunc
. It takes an http.ResponseWriter
and http.Request
as its arguments. People familiar with Java servlets would remember doing this!
To print out time, we import 'time' from the standard package and use it to respond back on the response writer object. By writing to http.ResponseWriter
object we can send the response to the client.
http.Request
is the structure that represents the HTTP request and hence has the entire request data. To access the URL path we do r.URL.path
.
When you run this and then access localhost:8080
you should see the current time on every refresh.
Accepting User Input
Now let's write an application which accepts a username
on the index page and then when the form is submitted, it greets the user on the next page.
Here's our Go code structure:
Lets first create an HTML file containing the form inside the public directory.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Go Greeter</title> </head> <body> <h1>Go Greeter</h1> <form action="/greet" method="post" accept-charset="utf-8"> <input type="text" name="username" id="username" value="Enter username..."> <input type="submit" value="Greet me!"> </form> </body> </html>
This form, on submit, will redirect to /greet
. Let's also write the contents of the greet.html
file inside the public directory, which we would render when the request comes to /greet
.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Go Greeter</title> </head> <body> <pre>Hello {{.}}</pre> </body> </html>
The Go code is as follows:
package main import ( "log" "net/http" "html/template" ) func main() { http.HandleFunc("/", root) http.HandleFunc("/greet", greeter) log.Println("Listening...") err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } } func root(w http.ResponseWriter, r *http.Request) { t, _ := template.ParseFiles("public/index.html") t.Execute(w, nil) } func greeter(w http.ResponseWriter, r *http.Request) { username := r.FormValue("username") t, _ := template.ParseFiles("public/greeter.html") err := t.Execute(w, username) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
We've used html/template
to keep the HTML code in templates and then using them to render, on request.
There is a curious looking {{.}}
in the greeter.html
file. The html/template
package assumes that plain text is always produced. It adds escaping wherever necessary to safely embed that plain string in correct context. When a data value is not plain text, we can make sure it is not escaped by specifying its type. So essentially, Hey, {{.}}!
can be invoked by using tmpl.Execute(out, HTML('<i>Nishant</i>'))
to produce Hey, <i>Nishant</i>!
. Go ahead, try that!
Since the basic application is now working, we can finally deploy it to Heroku.
Deploying to Heroku
Once you have the heroku-toolbelt correctly setup and the repo managed via Git, we can deploy it along these lines.
The only change we would need to do in the code for deploying to Heroku, is change the line where we listen on a specific port.
Change:
http.ListenAndServe(":8080",...)
to:
http.ListenAndServe(":"+os.Getenv("PORT"),...
.
Heroku Setup
In order to deploy to Heroku, you will need a Heroku user account. You will also need a Heroku command-line client. Get it by installing the Heroku Toolbelt if not already.
Once installed, login using the Heroku account by saying heroku login
, and then upload your SSH key. With these things in place, you should be ready to deploy to Heroku.
Deploying the Application
In order to deploy to Heroku, we need the app to be stored in Git.
git init . git add -A . git commit -m 'first heroku go app'
We will also need a Procfile to tell Heroku that the command it needs to run for the web process is our app.
echo 'web: gogreeter' > Procfile
Go package dependencies are managed on Heroku with the help of Godep
packages.
Install Godep and save your dependencies using the following:
go get github.com/kr/godep godep save
Add these new files to Git:
git add -A . git commit -m 'godep'
Finally, create the Heroku application. It can be done like so:
heroku create -b https://github.com/kr/heroku-buildpack-go.git
This should create a Git remote in your repository by the name of heroku
. You are ready to deploy now! Run the following:
git push heroku master
After the above command completes, your app should be up and running!
Go visit the URL by saying heroku open
or by directly visiting the app URL that you see in the console.
That's it. You now have a Go application up and running on Heroku!
Summary
In this tutorial we learned how easy it is to develop a Go web application and also deploy it on Heroku. These days, web development is largely dependent on the frameworks that one uses. To explore some of these options, you should definitely check some of these projects.
- Hugo
- Martini
- Revel
- Gorilla web toolkit
- Hastie - Static site generator in Go
Comments