Deploy Golang Web Application to Heroku cloud Platform

Here I will provide you the details to deploy simple golang web application on Heroku. 

I hope reader of this post has already installed Golang package and have basic knowledge about golang and basic skill about git not mandatory.


I am using go1.6 version on Linux-Ubuntu machine for this post.


sujin@sujin:~$ lsb_release -d

Description: Ubuntu 14.04.4 LTS

sujin@sujin:~$ go version

go version go1.6 linux/amd64

Setup Go directory structure and set GOPATH env variable. add GOPATH/bin to PATH env variable.


set working directory in GOPATH


sujin@sujin:~$ echo $GOPATH
/home/sujin/godir/work

create a simple web app in golang. For this example i create a folder called HerokuTest, inside a file called HerokuTest.go that contain program below

package main



import (

"fmt"

"net/http"

"os"
)

func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "\n\tHello World From Golang on Heroku")
}

func main() {
http.HandleFunc("/", homeHandler)

fmt.Println("Server Listening...")
err := http.ListenAndServe(":"+os.Getenv("PORT"), nil)
if err != nil {
panic("ListenAndServe")
}
}

Compile and test the program locally

sujin@sujin:~/godir/work/src/blog/HerokuTest$ go build
sujin@sujin:~/godir/work/src/blog/HerokuTest$ ls
HerokuTest  HerokuTest.go
sujin@sujin:~/godir/work/src/blog/HerokuTest$ PORT=7070 HerokuTest 
Server Listening...

Go to the url http://127.0.0.1:7070/ from web browser it will print Hello World From Golang on Heroku in web page.

We should manage dependency package using Godep

install godep

go get github.com/kr/godep

save all golang dependencies

sujin@sujin:~/godir/work/src/blog/HerokuTest$ godep savesujin@sujin:~/godir/work/src/blog/HerokuTest$ ls Godeps HerokuTest HerokuTest.go

We should create Procfile to tell Heroku which command to execute on web

sujin@sujin:~/godir/work/src/blog/HerokuTest$ echo 'web: HerokTest' > Procfile

Now its time to configure git for the project.

git init
git add .
git git commit -m "Heroku Test Project Initial Commit"
git remote add origin https://github.com/sujinsr/HerokuTest.git
git push origin master


Register in heroku website to get free account https://signup.heroku.com/?c=70130000001x9jFAAQ


install heroku tool belt

sujin@sujin:~/godir/work/src/blog$ heroku login
Enter your Heroku credentials.
Email: sujinsr@gmail.com
Password (typing will be hidden): 
Logged in as sujinsr@gmail.com


Pull the HerokuTest project from git

go get github.com/sujinsr/HerokuTest/...


Move to project directory and create heroku instance for your application




sujin@sujin:~/godir/work/src/github.com/sujinsr/HerokuTest$ heroku create heroku-test-app-blog -b https://github.com/kr/heroku-buildpack-go.git
Creating heroku-test-app-blog... done, stack is cedar-14
Setting buildpack to https://github.com/kr/heroku-buildpack-go.git... done
https://heroku-test-app-blog.herokuapp.com/ | https://git.heroku.com/heroku-test-app-blog.git

Now push your application to git heroku master

sujin@sujin:~/godir/work/src/github.com/sujinsr/HerokuTest$ git push heroku master
Counting objects: 14, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 1.48 KiB | 0 bytes/s, done.
Total 14 (delta 2), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Fetching set buildpack https://github.com/kr/heroku-buildpack-go.git... done
remote: -----> Go app detected
remote: -----> Checking Godeps/Godeps.json file.
remote: -----> Installing go1.6... done
remote: -----> Running: godep go install -tags heroku ./...
remote: 
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: 
remote: -----> Compressing...
remote:        Done: 2.2M
remote: -----> Launching...
remote:        Released v3
remote:        https://heroku-test-app-blog.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy.... done.
To https://git.heroku.com/heroku-test-app-blog.git
 * [new branch]      master -> master

Check whether application running

sujin@sujin:~/godir/work/src/github.com/sujinsr/HerokuTest$ heroku ps
=== web (Free): HerokuTest (1)
web.1: up 2016/02/28 14:09:45 +0530 (~ 37s ago)

Check the aplication by running heroku open

sujin@sujin:~/godir/work/src/github.com/sujinsr/HerokuTest$ heroku open
Opening heroku-test-app-blog... done
Created new window in existing browser session.


Check the logs 

sujin@sujin:~/godir/work/src/github.com/sujinsr/HerokuTest$ heroku logs --tail
2016-02-28T08:38:42.408669+00:00 heroku[api]: Enable Logplex by sujinsr@gmail.com
2016-02-28T08:38:42.408669+00:00 heroku[api]: Release v2 created by sujinsr@gmail.com
2016-02-28T08:39:43.323594+00:00 heroku[api]: Scale to web=1 by sujinsr@gmail.com
2016-02-28T08:39:43.566013+00:00 heroku[slug-compiler]: Slug compilation started
2016-02-28T08:39:43.566018+00:00 heroku[slug-compiler]: Slug compilation finished
2016-02-28T08:39:43.414709+00:00 heroku[api]: Deploy 51ae268 by sujinsr@gmail.com
2016-02-28T08:39:43.414779+00:00 heroku[api]: Release v3 created by sujinsr@gmail.com
2016-02-28T08:39:44.250976+00:00 heroku[web.1]: Starting process with command `HerokuTest`
2016-02-28T08:39:45.250323+00:00 app[web.1]: Server Listening...
2016-02-28T08:39:45.844980+00:00 heroku[web.1]: State changed from starting to up

Connect Redis from Golang


In this article i am not going to say how Redis and golang works, I hope you have basic knowledge of both. Instead I will tell you how to connect to redis server and execute command from golang. 

In case you don't have the knowledge on Redis & Golang please check their official websites (GOLANG & REDIS) for documentation and more information.

I believe you have already installed golang and redis server in your laptop/PC. If not please check their official website for installation procedure.

Redis server written in C programming language but it has client available for most of the programming language. There is more libraries available for golang as well. I am going to use Redigo because it has many feature and easy to use. You can check their github website [ Redigo github ] for source code and documents

You can download the Redigo redis client library for golang using the go get command like below
          go get github.com/garyburd/redigo/redis
You should configure GOPATH environment variable to succeed this command.

Here I provide the simple program to connect redis server from golang and query redis SET & GET command.

Example Program:

package main

import (
    "fmt"
    "github.com/garyburd/redigo/redis"
    "log"
)

func main() {
    /* Connect With Redis Server */
    r, err := redis.Dial("tcp", ":7777")
    if err != nil {
        fmt.Println("Error ", err)
    }
    fmt.Println("Connection Success With Redis Server")

    /* Query Redis Commands */
    _, err = r.Do("SET", "Name1", "Michel")
    if err != nil {
        log.Fatal("Error to SET", err)
    }
    fmt.Println("SET Success")

    value, err := redis.String(r.Do("Get", "Name1"))
    if err != nil {
        log.Fatal("Error to GET", err)
    }
    fmt.Println("GET Success: Name1 =", value)

    /* Close Redis Server Connection*/
    r.Close()

}

Output:

Connection Success With Redis Server
SET Success

GET Success: Name1 = Michel


Source Code Explanation:

In this example code i used two redigo api calls Dial which help to connect redis server and Do execute redis command.

r, err := redis.Dial("tcp", ":7777")

This statement connect help to connect your redis server running in port number 7777 using tcp connection. It return error and redis handler which help for other redigo APIs.

    _, err = r.Do("SET", "Name1", "Michel")

DO api will execute redis SET command with key as "Name1" and value as "Michel". Here "r" is handle returned from previous Dial API. This statement is similar to executing redis command "SET Name1 Michel" from redis CLI client.

    value, err := redis.String(r.Do("Get", "Name1"))

This statement get the redis key with name as "Name1" and convert to string format. This is similar to executing "GET NAME1" .

    r.Close()

This statement used to close redis connection.

Buffered io reader and writer in Golang


Writing to file using buffered writer

package main

import (
"bufio"
"log"
"os"
)

func main() {
/* Create and Open file for writing */
filefd, err := os.Create("blog.txt")
if err != nil {
log.Fatal(err)
}
defer filefd.Close()

/* create buffered write handler for opened file */
bufWriteHandle := bufio.NewWriter(filefd)

/* Write bytes to buffer */
byteData := []byte{'a', 'b', 'c', 'd', 'e', '\n'}
nn, err := bufWriteHandle.Write(byteData)
if err != nil {
log.Fatal(err)
}
log.Println("Number of bytes Written to buffer", nn)

/* Write String to buffer */
nn, err = bufWriteHandle.WriteString("String written using bufferd io\n")
log.Println("Number of bytes Written to buffer", nn)

/* flush from buffer to disk */
bufWriteHandle.Flush()
}


Reading from file using buffered reader

package main

import (
"log"
"os"
"bufio"
"fmt"
)

func main() {
/* Open existing file for reading */
filefd, err := os.Open("blog.txt")
if err != nil {
log.Fatal(err)
}
defer filefd.Close()

/* Create buffered read handler for opened file */
bufReadHandle := bufio.NewReader(filefd)

/* allocate slice of bytes to read */
readBytes := make([]byte, 64)

/* Read bytes and move pointer */
nn, err := bufReadHandle.Read(readBytes)
if err != nil {
log.Fatal(err)
}
fmt.Println("Number of bytes read", nn)
fmt.Println("Read Bytes:", string(readBytes))
}

Simple HTTP Web Server in Golang

PROGRAM:

package main

import (
"fmt"
"net/http"
)

func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Inside homeHandler...")
/* Write text to web page */
fmt.Fprintf(w, "Hi, This is from Home Handler")
}

func page1Handler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Inside page1Handler...")
fmt.Fprintf(w, "Hello, This is from Page 1 Handler")
}

func page2Handler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Inside page2Handler...")
fmt.Fprintf(w, "Hello, This is from Page 2 Handler")
}

func main() {
/* Add handler */
http.HandleFunc("/", homeHandler)
http.HandleFunc("/page1", page1Handler);
http.HandleFunc("/page2", page2Handler);

/* Listen on a port */
fmt.Println("Listening...")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println("ERROR: ListenAndServe:", err)
}
}


Container list in Golang

PROGRAM:

package main

import (
"container/list"
"fmt"
)

func displayList(l *list.List) {
/* Traverse the list */
for e := l.Front(); e != nil; e = e.Next() {
fmt.Printf("%d ", e.Value)
}
fmt.Printf("\n")
}

func removeList(l *list.List, data int) {
/* Traverse the list and check */
for e := l.Front(); e != nil; e = e.Next() {
if e.Value == data {
l.Remove(e)
}
}
}

func main() {
/* Create the list */
mylist := list.New()

/* Push element at end */
mylist.PushBack(10)
mylist.PushBack(20)
fmt.Printf("Count-%d: ", mylist.Len())
displayList(mylist)

/* Push element at first */
mylist.PushFront(13)
mylist.PushFront(17)
fmt.Printf("Count-%d: ", mylist.Len())
displayList(mylist)

/* Remove element from list */
removeList(mylist, 10)
fmt.Printf("Count-%d: ", mylist.Len())
displayList(mylist)

/* Clear the list */
mylist.Init()
fmt.Printf("Count-%d: ", mylist.Len())
displayList(mylist)
}

OUTPUT:

sujin@sujin:~/workspace/go$ go build list.go

sujin@sujin:~/workspace/go$ ./list
Count-2: 10 20 
Count-4: 17 13 10 20 
Count-3: 17 13 20 
Count-0: