Go Tutorial with MongoDB on Heorku

I've spent the last couple of days digging into Go and getting the feel for it and so far I really like it. It built a small web app using MongoDB and Heroku and thought I would share the process. Here is the source code and you can run the application here to get a feel for how it works. It's a simple app that allows people to post images or videos of where they work, i.e., their 'cribs'.

Go is different than most other languages in a number of ways. It's not about object-oriented programming or functional programming. It about getting stuff done. Build times are almost negligible and the code runs super fast. It's concurrency model is very powerful and it’s standard library provides almost everything you need out of the box. For a good overview of what Go is, how it was devised and why it is so cool, check out this blog post.

Learning Golang

Here are some links that I found useful. For installation, the Getting Start docs should work for you but you may want to take a peek at this short screencast.

I started off with the interactive Tour of Go. The tour is divided into three sections: basic concepts, methods and interfaces, and concurrency. Throughout the tour you will find a series of exercises for you to complete. Click the Run button for each section to compile and run the program on a remote server. No software installation needed to get start playing. If you are feeling adventurous, you can head over to the Go Playground and run your own code. Great for testing snippet you find or code you want to experiment with.

You definitely want to check out the Go docs and language specs next.

I found How to Write Go Code a god start as it demonstrates the development of a simple Go package and introduces the go tool, the standard way to fetch, build, test and install Go packages and commands. However, if you prefer, there is a video version instead.

A must read for any new Go programmer is Effective Go. The document gives tips for writing clear, idiomatic Go code.

Books

If you prefer books (or PDFs of books), I found the following to be really helpful:

An Introduction to Programming in Go

Learning Go - a free PDF for learning the Go language. You can build the code yourself or download the PDF

Go Bootcamp (by Matt Aimonetti) - The PDF is available here.

Resource Sites

I think my favorite site is Learn X in Y minutes, Where X=Go. The site has one long Go file with a ton of effective commenting that teaches concepts along the way. I really love this site.

Go by Example is a hands-on introduction to Go using annotated example programs.

If you are fan of Railscasts, there a Gophercasts with a couple of good videos, especially for Postgres and Martini.

And finally Go (Golang) Pointers in 5 Minutes covers of course pointers in Go. Not surprising.

Go Help

If you need a little help now and then, there is of course Stackoverflow and the go-nuts IRC channel, freenode.net#go-nuts. If you are keen on Slack, Gohper Academy just announced a new Slack community you can join.

Building Topcoder 'Cribs'

I learn best by doing so I looked around for something to build. I wanted something a little more than a hello world but definitely not production quality. One thing we want to do with topcoder is allow members to post pictures and video of where they work, i.e., their cribs.

So the first thing I did was look around for a web framework for Go. There's a great reddit thread with a ton of info. The Square Engineering blog also has an in-depth analysis as well with their winner. I finally decided to use Martini for a couple of reasons: 1) it smells a lot like Express and Sinatra so it was easy for me to grok, has a huge community and seems to be growing by leaps and bounds.

Let's walk through some of the code. Server.go is where all of the action happens. It's pretty small but straight forward and well documented so you can see what's going on.

package main

import (  
  "os"
  "github.com/codegangsta/martini"
  "github.com/codegangsta/martini-contrib/render"
  "github.com/codegangsta/martini-contrib/binding"
  "labix.org/v2/mgo"
  "labix.org/v2/mgo/bson"
)

// the Crib struct that we can serialize and deserialize into Mongodb
type Crib struct {  
  Handle string `form:"handle"`
  URL  string `form:"url"`
  Type string `form:"type"`  
  Description string `form:"description"`
}

/* 
   the function returns a martini.Handler which is called on each request. We simply clone 
   the session for each request and close it when the request is complete. The call to c.Map 
   maps an instance of *mgo.Database to the request context. Then *mgo.Database
   is injected into each handler function.
*/
func DB() martini.Handler {  
  session, err := mgo.Dial(os.Getenv("MONGO_URL")) // mongodb://localhost
  if err != nil {
    panic(err)
  }

  return func(c martini.Context) {
    s := session.Clone()
    c.Map(s.DB(os.Getenv("MONGO_DB"))) // local
    defer s.Close()
    c.Next()
  }
}

// function to return an array of all Cribs from mondodb
func All(db *mgo.Database) []Crib {  
  var cribs []Crib
  db.C("cribs").Find(nil).All(&cribs)
  return cribs
}

// function to return a specific Crib by handle
func Fetch(db *mgo.Database, handle string) Crib {  
  var crib Crib
  db.C("cribs").Find(bson.M{"handle": handle}).One(&crib)
  return crib
}

func main() {

  m := martini.Classic()
  // specify the layout to use when rendering HTML
  m.Use(render.Renderer(render.Options {
    Layout: "layout",
  }))
  // use the Mongo middleware
  m.Use(DB())

  // list of all cribs
  m.Get("/", func(r render.Render, db *mgo.Database) {
    r.HTML(200, "list", All(db))
  })  

  /* 
    create a new crib the form submission. Contains some martini magic. The call 
    to binding.Form(Crib{}) parses out form data when the request comes in. 
    It binds the data to the struct, maps it to the request context  and
    injects into our next handler function to insert into Mongodb.
 */   
  m.Post("/", binding.Form(Crib{}), func(crib Crib, r render.Render, db *mgo.Database) {
    db.C("cribs").Insert(crib)
    r.HTML(200, "list", All(db))
  })  

  // display the crib for a specific user
  m.Get("/:handle", func(params martini.Params, r render.Render, db *mgo.Database) {
    r.HTML(200, "display", Fetch(db, params["handle"]))    
  })    

  m.Run()

}

Here is the layout template the all of the views use. The HTML for each view is injected into the layout.

<!doctype html>  
<html>  
<head>  
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Topcoder Cribs</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.5.0/pure-min.css">
</head>

<body style="margin: 20px;">  
<h1>Topcoder Cribs!</h1>  
{{ yield }}
</body>  
</html>  

The home page iterates over the array of all returned Cribs from mongodb and links them to the display page. It also contains a form to post new Cribs.

<h2>Members' Cribs</h2>  
<ul>  
{{range .}}
  <li><a href="/{{.Handle}}">{{.Handle}}</a></li>
{{ end }}
</ul>

<form class="pure-form pure-form-stacked" style="padding-top:25px" action="/" method="POST">  
    <fieldset>
        <legend>Add Your Crib!</legend>

        <label for="handle">Handle</label>
        <input id="handle" name="handle" type="text" placeholder="Your handle">

        <label for="url">URL</label>
        <input id="url" name="url" type="text" placeholder="Complete URL for images or just the ID for videos" style="width: 400px">


        <label for="type">Type</label>
        <select id="type" name="type">
            <option>Image</option>            
            <option>Youtube</option>
            <option>Vimeo</option>
        </select>            

        <label for="description">Description</label>
        <textarea id="description" name="description" rows="5" cols="50"></textarea>

        <button type="submit" class="pure-button pure-button-primary">Submit</button>
    </fieldset>
</form>  

Any finally the display page shows an image, youtube video or vimeo video based upon the type of Crib.

<h2>{{.Handle}}'s Crib</h2>

{{ if eq .Type "Youtube" }} 
  <iframe width="560" height="315" src="//www.youtube.com/embed/{{ .URL }}" frameborder="0" allowfullscreen></iframe>
{{ else if eq .Type "Vimeo" }} 
  <iframe src="//player.vimeo.com/video/{{ .URL }}" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
{{ else }}
  <img src="{{ .URL }}">
{{end}}

<p>{{ .Description }}</p>  

Deploying to Heorku

If you are deploying to Heroku you'll need to add the following files. The Heroku buildpack needs to know where to put your code in the image. Add the .godir file in your project root with your directory structure:

github.com/topcoderinc/cribs  

You'll also need a Procfile in your project root so heroku knows what type of dyno to spin up:

web: cribs -port=$PORT  

Finally, when creating your application add the buildpack flag and don't forget to add the Mongodb and environment variables:

// create
heroku create -b https://github.com/kr/heroku-buildpack-go.git my-app

// add the mongolabs addon
heroku addons:add mongolab

// add the envrironment variables for mongolab. see environment.sh

Wrapup

So now I have my first Go application running and am fairly happy with it. However, after building the app, reading this rebuttal of Martini and talking with a couple of Appirians that use Go, I'm thinking of scrapping Martini and using simply the standard Go library. Here's an interesting blog post that I have been looking at regarding this.

In the next blog post, I plan on deploying my app to AWS with Docker.