The Building of Go Wiki – Part 1

I recently completed my first true project in Go: a fully RESTful wiki that is persistent through a MongoDB database. Since Go is such an upcoming language that many of us haven’t been exposed to yet, I wanted to write about how I built it and go through some of the architecture involved with the wiki in case anyone is interested in how Go works. If you have any feedback for me, let me know!

Check out the live site and the GitHub repo.

The Main File

Let’s jump right into the main file that starts off this wiki:

Just like C, C++, and Java, Go looks for a main method to start everything off. We’ll get more into the guts down below, but starting off in the first few lines we’re importing some necessary Go packages. After that, we’re reading a config file in order to set some global configuration, and then we’re establishing connections with the MongoDB collection. The rest of the main method is dedicated to starting a simple HTTP server on port 8080, and routing different urls to certain handlers.

You may notice the use of the keyword go here; no that’s not just a fancy way to say I’m using Go – it forces the function passed to it to run as a goroutine. Go is built around the concept of concurrency, and therefore it’s very easy to run commands in their own ‘goroutine,’ or thread. Additionally, Go also makes it very easy to talk between those threads using ‘channels,’ which are very useful, but not discussed in this post because I don’t need to communicate between goroutines. In fact, I am running each handler in its own goroutine because each handler is very modular in nature, and doesn’t depend on any other handler.

Reading Configuration

Reading configuration in Go isn’t a default feature, but we can do it with the help of a package called gcfg, which allows you to create config files similar to an INI file. Here is an example config file structured properly for Go Wiki:

Then in our code, gcfg allows us to create a Go struct (similar to a struct in C, and a class in an OOP language) out of this config file like so:

Because the Cfg variable and ReadConfig() method start with capital letters, they have public scope and can be accessed outside of their main package after being imported; otherwise, they would be private variables and functions. If the config can’t be read properly, the program exits with an error.

Establishing DB Connections

Go Wiki uses MongoDB, and there’s a very well-built ORM for Go that I chose to use called mgo. I’m very impressed with how all-encapsulating mgo is considering how new Go is, and it handles all interactions with the mongo API beautifully. Let’s take a look at how we use mgo:

This establishes a connection based off our previously established config, and sets the desired collection to our global Collection variable, which is the only collection we deal with in this wiki.

The Page Struct

The core of this wiki revolves around a struct called Page. This is the struct that we use to encapsulate our attributes for each wiki entry, and also has methods associated with it such as loading, deleting, and saving an entry to the database. Here is our main page.go file which houses all page-related code:

There’s a lot going on here, but in nutshell, we create a Page struct that holds title and body attributes, and then we give it methods for saving, deleting, and loading an entry from the database.

Here’s an awesome bit about Go – you may have noticed that the Delete and Save methods are preceded with a set of parameters. In Go, this is what is called the receiver, and it declares the variable that has parent scope over that function; in layman’s terms, it becomes the ‘this’ of the function, but assigned to whatever variable you want. If you’re familiar with javascript, it is similar to running .bind(this) after a function call, which redefines the ‘this’ value to the scope outside that function.

For the Save and Delete functions, we set the receiver as a Page struct so that we can directly use the calling Page instance with all of its attributes in the function (remember that Go is not an OOP language, so the ideas of OOP encapsulation don’t exist here). We’ll see how to use these methods in our route handlers.

How About the Route Handlers?

Now that we’ve established our foundation for the Go Wiki, we need to handle the logic that happens when we navigate to the wiki itself and interact with it. But I think we’ve covered enough here for one day; we’ve established a firm foundation where we have our ORM set up based up on configurable options, and we’ve set our architecture up to be able to handle creating and modifying wiki entries. Next time we’ll cover in-depth using Go’s net/http package to validate and extract parameters from our URL, handle actual logic such as interacting with the DB, and use the net/http package’s templating language to access our Go variables in our actual HTML templates (similar to how ERB, Twig, Handlebars, etc. work).

Stay tuned!

  • Egon Elbre

    go http.HandleFunc(“/view/”, helpers.MakeHandler(routes.ViewHandler))

    Running that in goroutine isn’t necessary, that call only registers the handlers… but it doesn’t do any handling itself.

    > Go Wiki uses MongoDB, and there’s a very well-built ORM for Go that I chose to use called mgo.

    mgo is not an ORM, at least not by standard usages of ORM.

    import “../globals”

    Don’t use relative imports.

    globals – I’m not sure that package is a good design decision.

    helpers – that code can be organized much better, try to get rid of utils/helpers packages. Also read [Your coding conventions are hurting you](