Go Web App Walkthrough

As a follow up to my previous post, I thought I would walk through the basic web app I built using Go, Gin, and GORM. I realize this might not be the most idiomatic Go program, but I was going for simplicity and brevity.

You can find this code in the file main.go in my goweb GitHub repo.

The Code

Every Go application starts with a package definition. Since this program is an executable and not a library, call this package main. This tells the compiler that the main function, where execution starts, is found here.

package main

Next, import libraries needed by the program. In this case gin and gorm, as mentioned earlier, as well as the GORM postgres driver. The program needs godotenv and os for loading environment variables and finally net/http which defines HTTP status codes.

import (
    "github.com/gin-gonic/gin"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/postgres"
    "github.com/joho/godotenv"
    "net/http"
    "os"
)

Next, define the User model. This is a standard Go struct that includes gorm.Model. This adds ID and time stamp fields.

type User struct {
    gorm.Model
    Name string
}

The global variable db is used throughout the program to send queries to the database.

var db *gorm.DB

The usersIndex function is a request handler. It finds an array of users in the database and uses the Gin context to render them as HTML using the index.html template.

func usersIndex(c *gin.Context) {
    var users []User

    db.Find(&users)

    c.HTML(http.StatusOK, "index.html", gin.H{
        "users": users,
    })
}

Finally, the main function, where execution begins.

func main() {

First, load the contents of the .env file. If there’s an error, panic. That is, end the program with an error message.

    err := godotenv.Load()
    if err != nil {
        panic("Error loading .env file")
    }

Now that the environment is loaded, use the DATABASE_URL variable to connect to the database. Again, panic if there is an error. The defer statement calls dB.Close() when this function ends to close the database connection.

    db, err = gorm.Open("postgres", os.Getenv("DATABASE_URL"))
    if err != nil {
        panic(err)
    }
    defer db.Close()

Use the connection to auto migrate the database. This creates the users table, based on the plural version of the model name, with columns named id, created_at, updated_at, deleted_at, and name.

    db.AutoMigrate(&User{})

Next, count the number of users in the database. If there are zero users, create a few examples. You might think of this as seed data.

    count := 0
    db.Table("users").Count(&count)

    if count == 0 {
        db.Create(&User{Name: "Alice"})
        db.Create(&User{Name: "Bob"})
        db.Create(&User{Name: "Carol"})
    }

Create a Gin router using gin.Default().

    router := gin.Default()

Tell the router where to find static files, such as CSS, JavaScript, and images. Also, load the HTML files in the templates directory.

    router.Static("/assets", "./assets")
    router.LoadHTMLGlob("templates/*")

Next, tell the router to handle GET requests to the root path by calling the usersIndex function defined earlier.

    router.GET("/", usersIndex)

Finally, call router.Run() to start handling requests in a loop.

    router.Run()
}

And with that you have a complete program that uses data from a database to render HTML templates in response to web requests.

From Rails to Go

A recent project at work required a high performance API and a light-weight front end. I’ve been looking for an opportunity to explore other languages and frameworks and this seemed like a perfect opportunity. We already have a few services written in Go, so I decided to start there.

The Go Programming Language is a “fast, statically typed, compiled language.” In other words, very different from Ruby (which is dynamically typed and interpreted). In Ruby, everything is an object; Go doesn’t have classes. Yes, very different.

Web

With my choice of programming language set, it was time to find a web framework. After a bit of Googling, I came upon Gin. It promises “performance and productivity” which is exactly what I needed.

Gin features a very fast router for processing requests as well as easy rendering of responses in JSON or HTML. Gin uses the html/template package for rendering dynamic HTML pages (also see text/template for complete documentation).

Database

The next step was database access. I typically work with Active Record, so I started searching for something similar. GORM is an ORM Library in Go. It is full-featured (almost) and developer friendly. Its API is similar to Active Record and it supports all of the features I need including a PostgreSQL driver.

Creating models is easy using GORM. Define the model as a Go struct and include gorm.Model to add ID and timestamp columns. Then pass the model to db.AutoMigrate and GORM will create a table with the required columns automagically. The migration doc has examples of automatic and manual migrations.

Miscellaneous

Since I plan on eventually deploying this application to Heroku, and Heroku uses an environment variable for the DATABASE_URL, I’m also using the Go port of Ruby’s dotenv project named godotenv to load environment variables in development.

Sample App

I posted a complete sample application named goweb on GitHub. Feel free to clone that repo as a starting point for your own creations. The README file includes instructions for setting everything up on a Mac with Homebrew.

If you aren’t on a Mac, you should be able to follow the Go installation instructions and then download PostgreSQL to get the sample app running. Hopefully this will help others looking to explore web development with Go.

On Dwitter

I’m not going to post about this every day, but in case you missed my last post, this is the first day of #The100DayProject. To see what it’s about, search for #the100dayproject on Instagram.

My first creation is a JavaScript animation on Dwitter.net. I posted the video below on Instagram, but the real thing looks much better. Especially in full screen.

If you haven’t heard of Dwitter.net, its creators describe it like this:

Dwitter.net is a challenge to see what awesomeness you can create when limited to only 140 characters of javascript and a canvas.

I would also say that it’s a great way to kill a few spare minutes during the day. It’s fun and you’ll probably learn something in the process. I wrote code this morning while enjoying a cappuccino.

If you’re interested in JavaScript, go to my first dweet to see the 76 characters that make this work. Also, check out my Dwitter.net profile for future creations. Hopefully my next dweet will be a little more colorful.

The 100 Day Project

It seems like I’m always looking for new creative outlets, but rarely finding them. There are plenty of things I want to do — working on one of my writing projects, coding creative programs, etc. But it seems like I never have the time.

I know that lack of time isn’t really the problem. I just haven’t prioritized creative outlets and developed a habit. A great way to build a habit is to try to do something for an extended period of time and make yourself publicity accountable.

With that in mind, I was happy to come across the fifth annual The 100 Day Project, a “free, global art project that anyone can participate in.” Starting April 3rd, create something every day and post it on Instagram with the hashtag #The100DayProject.

I have a few ideas of things I want to work on, but no where near one hundred. They say “It’s okay if you miss a day! Keep going.” So that’s what I’ll do. Most of my “art” is writing, and I’m not really sure how that’s going to translate to Instagram, but it should be fun.

I hope to keep up around weekly blog posts here and work on some unannounced projects, too. Who knows, maybe in a hundred days I’ll be able to announce something new?