Introduction to Writing Web Apps in Golang

Full stack developer @        RainingClouds 

  • Golang => Web Apps, System Apps
  • Android => System Framework, Apps
  • Objective C => iOS
  • Scala => Play
  • Java => Netty, Play
  • Angular JS => Web app front end
  • Python => Django, Flask
  • HTML , Actionscript => Unfortunate

Why Go

Go web API:

  • 20,000 samples
  • 0 errors
  • Average: 8ms
  • Median: 5ms
  •  90%: 20ms
  • Max: 90ms
  • Min: 1ms
  • Throughput: 1202.2 requests/s 4691.79 requests/s (see update) 
  • Memory usage: 10MBs

Rails (Rails 4, Ruby 2.0, production mode, puma web server):

  • 20,000 samples
  • 0 errors
  • Average: 187ms
  • Median: 163ms
  •  90%: 214ms
  • Min: 9ms
  • Max: 178,552ms (442ms most of the time but big spike around 15,000 requests)
  • Throughput: 88.9 requests/s

      Memory usage: 117MBs

Benchmarks by Matt Aimonetti

Go

  • Compiled language
  • Statically typed
  • Concurrent
  • Garbage-collected
  • High speed compilation
  • Highly portable (including Andorid and soon on iOS as well)

Robert Griesemer, Ken Thompson, and Rob Pike

Web Apps

  • Tools
  • Framework
  • Dependency Management
  • DB Supports
  • ORM
  • Migration Supports
  • JSON Support
  • Go routines
  • Live reloads
  • Deployment
  • Error logging
  • Libraries
  • Community

Tools

Go 1.4

SublimeText 3
+
GoSublime

Postgresapp

Mongohub

Development Tools

Web Frameworks

  • Beego - beego is an open-source, high-performance web framework for the Go programming language.
  • Bone - Lightning Fast HTTP Multiplexer.
  • Gin - Gin is a web framework written in Go! It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity.
  • Goat - A minimalistic REST API server in Go
  • goose - Server Sent Events in Go
  • gocraft/web - A mux and middleware package in Go.

22 in Total

Web Frameworks

Web Frameworks

  • Golang philosophy believes in library format
  • So usually (debatable) don't go for frameworks like revel (~Rails) which is convention based
  • Try to avoid reflection as much as possible (revel, martini are heavily using refections)
  • I go for Gin (slightly modified though)

Web Frameworks

Gin(https://github.com/gin-gonic/gin)

func getPort() string {
	var port = os.Getenv("PORT")
	// Set a default port if there is nothing in the environment
	if port == "" {
		port = "4747"
	}
	return ":" + port
}

func main() {
	engine := gin.Default()
	gin.SetMode(gin.ReleaseMode)
	// pushing routes
	pushRoutes(engine)
	log.Println("Starting server", getPort())
	// start http server
	engine.Run(getPort())
}

Web Frameworks

Gin(https://github.com/gin-gonic/gin)

func UserLogin(c *gin.Context) {
	c.AddHeader("Access-Control-Allow-Origin", "*")
	var bodyMap map[string]interface{}
	c.Bind(&bodyMap)
	log.Println(bodyMap)
	user, err := models.AuthenticateUser
(bodyMap["email"].(string), bodyMap["password"].(string))
	if err != nil {
		c.JSON(http.StatusUnauthorized, 
gin.H{"success": false, "message": "Email/Password is wrong"})
		return
	}
	if !user.IsActivated {
		c.JSON(http.StatusUnauthorized, 
gin.H{"success": false, 
"message": "User is not activated yet !!\nPlease check your Email"})
		return
	}
	c.JSON(http.StatusOK, 
gin.H{"success": true, "session_key": user.SessionKey, "user": user})
}

Dependency Management

Godep (https://github.com/tools/godep)

Command godep helps build packages reproducibly by fixing their dependencies.

// to save your current dependecies
godep save
// on updating dependecies
godep update
// to restore the dependecies
godep restore

Highly recommended as Golang libraries are cutting edge and some of the changes might break your webapp, so always remain faithful to library versions unless you are sure about not getting caught naked !!

DB Support

Relational
NoSql

DB Support : Relational

  • go-adodb - Microsoft ActiveX Object DataBase driver for go that using database/sql.
  • go-mssqldb - Microsoft MSSQL driver prototype in go language.
  • go-oci8 - Oracle driver for go that using database/sql.
  • go-pgsql - A PostgreSQL client package for the Go Programming Language.
  • go-sql-driver/mysql - MySQL driver for Go.
  • go-sqlite3 - SQLite3 driver for go that using database/sql.
  • pq - Pure Go Postgres driver for database/sql.

DB Support : NoSQL

  • aerospike-client-go - Aerospike client in Go language.
  • cayley - A graph database with support for multiple backends.
  • go-couchbase - Couchbase client in Go
  • gorethink - Go language driver for RethinkDB
  • gomemcache - memcache client library for the Go programming language.
  • mgo - MongoDB driver for the Go language that implements a rich and well tested selection of features under a very simple API following standard Go idioms.
  • neo4j - Neo4j Rest API Bindings for Golang
  • Neo4j-GO - Neo4j REST Client in golang.
  • redigo - Redigo is a Go client for the Redis database.
  • redis - A simple, powerful Redis client for Go.

DB Support

Don't confuse it with ORM, and don't worry Golang has plenty of ORM solutions

Golang also has drivers for elastic search

  • bleve - A modern text indexing library for go.
  • elastic - Elasticsearch client for Google Go.
  • elastigo - A Elasticsearch client library.
  • goes - A library to interact with Elasticsearch.

ORM

Object-relational mapping (ORM, O/RM, and O/R mapping) in computer science is a programming technique for converting data between incompatible type systems in object-oriented programming languages. This creates, in effect, a "virtual object database" that can be used from within the programming language.

Its crap

ORM means I don't have to write SQL :D

ORM

  • BeeDB - go ORM,support database/sql interface,pq/mysql/sqlite.
  • GORM - The fantastic ORM library for Golang, aims to be developer friendly.
  • gorp - Go Relational Persistence, ORM-ish library for Go.
  • hood - Database agnostic ORM for Go.
  • QBS - Stands for Query By Struct. A Go ORM.
  • upper.io/db - Single interface for interacting with different data sources through the use of adapters that wrap mature database drivers.
  • Xorm - Simple and powerful ORM for Go.

ORM

If you consider features of GORM wins single handedly. I have used it for almost 3 projects, and it really really works 

// get apk with id 
err := db.DB().Model(Apk{}).Where("id = ?", app.BuildId).Find(&apk).Error

// get list of apps for account with accountId and in descending order of updated_at
err := db.Where(App{AccountId: accountId}).Order("updated_at desc").Find(&apps).Error

// find IPhoneDeviceRegistration for device id and app id
err := db.DB().Model(IPhoneDeviceRegistration{}).Where("device_id = ? and app_id = ?"
                                        ,deviceId, appId).Find(®istration).Error
	

Migration Support

func PerformMigrations(db *gorm.DB) {
	log.Println("Running migrations")
	initial("init", db)
	second("removed gcm_id and app_id from device table 
            and added new registration entry", db)
	third("added apk_version_name column so as to track the live exceptions", db)
	fourth("added logcat to the exception", db)
	fifth("adding new ipa and ios device", db)
	sixth("added device name in ios device struct", db)
	seventh("added iphone device registration struct", db)
}

func initial(name string, db *gorm.DB) {
	// this is obvious
	db.AutoMigrate(&models.Migration{})
	if models.IsMigrationApplied(name) {
		log.Println("Migration", name, "is already applied")
		return
	}
	log.Println("Applying", name)
	db.DropTable(&models.Account{})
	db.AutoMigrate(&models.Account{})
	db.DropTable(&models.User{})
	db.AutoMigrate(&models.User{})
	db.DropTable(&models.App{})
	db.AutoMigrate(&models.App{})
	db.DropTable(&models.Apk{})
	db.AutoMigrate(&models.Apk{})
	db.DropTable(&models.AndroidDevice{})
	db.AutoMigrate(&models.AndroidDevice{})
	db.DropTable(&models.InviteRequest{})
	db.AutoMigrate(&models.InviteRequest{})
	db.DropTable(&models.AndroidException{})
	db.AutoMigrate(&models.AndroidException{})
	err := models.MigrationApplied(name)
	if err != nil {
		panic(err)
	}
	log.Println("Migration", name, "is applied")
}

func second(name string, db *gorm.DB) {

Depends upon how do you want migrations to work

JSON Support


type User struct {
	Id      int    `json:"user_id"`
	AuthKey string `json:"-" sql:"not null;unique"`

	IsActivated       bool   `json:"is_activated"`
	IsSessionKeyStale bool   `json:"-"`
	SessionKey        string `json:"-"`

	Name         string `json:"user_name" sql:"not null;"`
	EmailAddress string `json:"email_address" sql:"not null;"`
	Password     string `json:"-" sql:"not null"`

	AccountId int `json:"account_id" sql:"not null;"`

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
	DeletedAt time.Time `json:"deleted_at"`
}

Go has inbuilt JSON support (RFC 4627). (encoding/json)

Go Routines

....
app.BuildId = ipa.Id
err = app.Save()
if err != nil {
	handleError(c, err)
	return
}
// sending push notifications to all the devices if GCM id is available
go func(app *models.App) {
	deviceRegistrations, err := models.GetDeviceRegistrationsForAppId(app.Id)
	if err != nil {
		log.Println(err.Error())
		return
	}
	payload := make(map[string]interface{})
	payload["make"] = "dist-1234"
	payload["path"] = fmt.Sprintf("/app/%d/ipa", app.Id)
	payload["name"] = app.AppName
	payload["ver"] = app.Ipa.BundleVersion
	for _, deviceRegistration := range deviceRegistrations {
		gcm.SendMessage(1, deviceRegistration.GcmId, 
"<id>", payload)
	}
}(app)
c.JSON(http.StatusOK, gin.H{"success": true, "message": "Apk is uploaded succesfully"})

The most simple asynchronous task APIs

Live Reload

# akshay at Akshays-MacBook-Pro.local in ~/CodeBase/distribute/src/distribute on git:master x [12:23:33]
$ gin run 
[gin] listening on port 3000
[gin] ERROR! Build failed.
# distribute/controllers
controllers/appController.go:312: syntax error: nested func not allowed

[gin] Build Successful

Gin (not the framework!) (https://github.com/codegangsta/gin)

Deployment

Error logging

Almost any service that

has REST API

BugSnag

AirBrake

Sentry

Libraries

Golang is awesome, and there is awesome-go

https://github.com/avelino/awesome-go

Community

  • Github
  • Dropbox
  • Bitbucket
  • CloudFlare 
  • Canonical
  • Heroku
  • Zynga
  • Disqus
  • Flipboard
  • SendGrid
  • and many many more...

Q&A

@akshay_deo

akshay@rainingclouds.com

RainingClouds is hiring Golang developers. Please mail us at : ping@rainingclouds.com