Writing A Simple Electronic Realtime Poll with Go
Tags: go, realtime, pusher, poll
Published: 2018-01-10 02:04:04

---
title: Writing A Simple Electronic Realtime Poll with Go
published: true
description: Golang, known on the streets as Go, is gaining popularity since was announced in 2009, nine years after Go have demonstrated to be a simple but powerfull programming language and the cherry on top of the cake, pretty easy to learn. In this post we are going to create a realtime poll with it server side writen in Go, which was created as part of academic exercise in order to learn that awesome language
tags: go, realtime, pusher, poll
cover_image: https://images.pexels.com/photos/159353/survey-opinion-research-voting-fill-159353.jpeg?w=1260&h=750&dpr=2&auto=compress&cs=tinysrgb
---
*Originally published on my [blog](https://redknot.io/articles/writing-realtime-poll-w-go)*

Golang, known on the streets as Go, is gaining popularity since was announced in 2009, nine years after Go have demonstrated to be a simple but powerfull programming language and the cherry on top of the cake, pretty easy to learn. In this post we are going to create a realtime poll with it server side writen in Go, which was created as part of academic exercise in order to learn that awesome language.

The original project idea was taken from this awesome [article](https://www.codementor.io/christiannwamba/how-to-build-an-electronic-realtime-poll-in-5-steps-es41iluc9) writen by **Christian Nwamba** at *codementor.io*, basically in his post he built the realtime poll with NodeJS, to be honest that post liked me so much, and given that I wanted to taste something of Go flavors, I decided create my own poll version with Golang.

## First Steps

To be honest, I never write nothing with Go before, so my first step was installed it into my computer, which was pretty easy, was just a thing of navigate into [golang.org](https://golang.org/) website and download the right installer for my operative system, then use that installation wizard to complete the process, in a few minutes I had the Go core installed in my computer and ready to code. In order to test it, I used the `Hello, Wold!` example published on **Golang** website:

```go
package main

import "fmt"

func main() {
	fmt.Println("Hello, World")
}
```

After check that all works good using the command `go run hello.go` my next step was to prepare my code editor (*Visual Studio Code*) to work with Go, basically I found this great [extension](https://marketplace.visualstudio.com/items?itemName=lukehoban.Go) on the marketplace, after installed it, I  was ready to `Go`.

## My Plan

Essentially as the *Christian Nwamba* post, the project was divided in a few layers, three to be more specific, first the server which delivers the views and receive the votes, second the `Pusher` integration in order to give to the project that realtime feature, finally the views including the vote screen and results screen, for those views we use a few lines of `JavaScript` and `HTML` and `SemanticUI` to style it, in this post we are going to talk about the first two layers.

![](https://raw.githubusercontent.com/lexmartinez/go-realtime-poll/master/screenshots/screenshot-1.png)

## The Server

As we said before, our server side is in charge to deliver the views and receive the votes, so the backend design has the following endpoints :

|  Method | Path | Description |
|------|-------------|-----|
| `GET`  | `/` | Votes Screen |
| `POST`| `/`|   Votes reception |
| `GET`   | `/results`|Results Chart Screen|

To implement those endpoints and create the simple routing that we need, the `net/http` was used, then our main function looks like this

```go
func main() {
	http.HandleFunc("/", base)
	http.HandleFunc("/results", results)

	if err := http.ListenAndServe(":8080", nil); err != nil {
		panic(err)
	} else {
		fmt.Println("Polling server running at localhost:8080")
	}
}
```
In that snippet basically we tell to `Go` which routes we are going to dispatch and which function should handle those requests, also start the server at `8080` port. Let's see the handler functions separatelly:

### Results Handler
The results handler function is pretty basic, is in charge to deliver the results screen with results chart inside of it, the chart render and the `Pusher` listener is part of our `frontend` features so in our server side we just need to response with the `HTML`output stream, to do that I wanted to use a template engine implementation like `Pug`, fortunately I found this pretty package [`github.com/Joker/jade`](https://github.com/Joker/jade) the syntax is almost the same of pug so basically was all that we needed.

```go
func results(w http.ResponseWriter, r *http.Request) {
	dat, err := ioutil.ReadFile("./templates/results.pug")
	if err != nil {
		fmt.Printf("ReadFile error: %v", err)
		return
	}

	tmpl, err := jade.Parse("results", string(dat))
	if err != nil {
		fmt.Printf("Parse error: %v", err)
		return
	}

	keys := Keys{
		Key:   os.Getenv("APP_KEY"),
		Cluster: os.Getenv("APP_CLUSTER"),
	}

	goTpl, err := template.New("html").Parse(tmpl)
	if err != nil {
		fmt.Printf("\nTemplate parse error: %v", err)
		return
	}
	err = goTpl.Execute(w, keys)
	if err != nil {
		fmt.Printf("\nExecute error: %v", err)
		return
	}
}
```
Some footnotes, we read our external template files with `io/ioutil` package, also as parameters we are injecting a few enviroment variables to `Pusher`client connection, that enviroment variables are loaded from an external `.env` with [`github.com/alexsasharegan/dotenv`](https://github.com/alexsasharegan/dotenv) package.
![](https://raw.githubusercontent.com/lexmartinez/go-realtime-poll/master/screenshots/screenshot-3.png)


### Base Handler
The base function is going to handle the root requests, i.e. Deliver the vote screen and receive the votes (then send them to `Pusher`), let's see the `base` handler implementation

```go
func base(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost {
		vote(w,r)
	} else if r.Method == http.MethodGet {
		home(w,r)
	} else {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("400 - Unsupported Request Method!"))
	}
}
```
In this function in essence, we are routing our requests to two different subhandlers based on request method, the first one, `home`is basically the same to `results` handler, here is the `vote` handler implementation
```go
func vote (w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	option := r.Form.Get("option")

	client := pusher.Client{
		AppId: os.Getenv("APP_ID"),
		Key: os.Getenv("APP_KEY"),
		Secret: os.Getenv("APP_SECRET"),
		Cluster: os.Getenv("APP_CLUSTER"),
		Secure: true,
	}

	data := map[string]string{"vote": option}
	client.Trigger("tv-shows", "vote-event", data)

	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte("Success vote for: " + option))
}
```
In this snippet we receive the request data and get `option` field a.k.a our vote, then send it through `Pusher`using the pusher API package [`github.com/pusher/pusher-http-go`](https://github.com/pusher/pusher-http-go).

> Pusher is an awesome realtime notifications API that use websockets, if you want to use it and configure you have to sign up (there are a free mode) and configure your app, for more information about the app setup see the [Pusher docs](https://pusher.com/docs) 

![](https://raw.githubusercontent.com/lexmartinez/go-realtime-poll/master/screenshots/screenshot-2.png)

That's it! our poll server is alive!

>  - Complete source code for this exercise could be found on this [**Github repo**](https://github.com/lexmartinez/go-realtime-poll)
>  - Thanks for reading! comments, suggestions and [DMs](https://twitter.com/lex0316) are welcome!