Top Go Modules: Golang Web APIs with GORM

Every month GoCenter awards top performing modules a Gopher Badge as a mark of achievement. We’re writing about some of these top modules and how they’re used in Go.

Robert Greiseimer has called Go the language of cloud computing and while it’s no secret that Go has strong features that support the needs of microservice architecture, distributed systems, and large-scale enterprise applications, what is less talked about is that Go was also built with web development in mind from the start. In fact, many developers in the community are using Go for full-stack development and championing new modules and frameworks that make Go a strong language for the web. 

Let’s take a look at some of the ways that Golang and the expanding world of community-led Go modules supports data exchange in web apps. I’ll also show how to identify some quality modules through GoCenter, the free Go module proxy for the development community, and take an in-depth look at one of my favorites.

Golang Loves Data on the Web

Go has sophisticated web packages that are part of its core library. With the recent Golang 1.15 release, that core library has been updated with improvements to database/sql, database/sql/driver, net/http, and encoding/json that harden Go’s ability to work with web data. These changes add limitations that reduce the risk of large quantities of data services overusing stack memory as well as setting an idle time for database connections.

Web Server Creation

Go’s net/http package is part of the standard library and is designed to transport HTML from server to client. It does so using an http.Handler interface that creates its own web server. This library makes RESTful API development very easy, and with Go structs, big data applications can be mapped to a number of different databases and data types.

Launching the web service involves importing the net/http package and writing two functions.

package main
 
import (
    "fmt"
    "log"
    "net/http"
)
 
func homePage(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "Welcome to the HomePage!")
    fmt.Println("Endpoint Hit: homePage")
}
 
func handleRequests() {
    http.HandleFunc("/", homePage)
    log.Fatal(http.ListenAndServe(":10000", nil))
}
 
func main() {
    handleRequests()
}

 

From this very simple file, you’ve setup a functional web server. This server of course isn’t actually sending, storing, and retrieving information from the web to a database. To build in that functionality, we would created a basic CRUD application that can CREATE, READ, UPDATE and DELETE information in your API.

You can learn more details about using this package for creating RESTful APIs from an excellent tutorial by Elliot Forbes.

JSON

One way to send and receive information is to use Go’s core library encoding/json. This library makes it easy to read/write data from JSON to your Go Applications. JSON or Javascript Object Notation was built to encode and decode data across the web and is much more fit for the web than straight XML. Using key:value pairs, JSON reads more like plain-text and it’s readable data format can be utilized while building your full-stack applications in a way that avoids lengthy SQL. While JSON makes sending data easy, it still needs a way to speak to a database like PostgreSQL. 

Golang ORMs

Luckily, the Go community has built a number of Object Relational Mapping libraries (ORMs) to allow Go developers to use JSON key:value pair syntax and encoding to map directly to a SQL database like PostgreSQL. ORMs enable developers to use their native programming paradigm to map data to SQL. 

An ORM transforms your database information to Golang objects and vice-versa. When working with an ORM, instead of writing SQL queries directly into your application, you can map your data much better using Golang struct like this:

// User struct for my database
type User struct {
   gorm.Model
   firstName    string
   lastName     string
   email        string
   message      string
   profession   string
   age          int
   zipCode      int
}

 

Not everyone is a fan of using ORMs because they create a level of abstraction from the actual data being stored in the database. Depending on which library you use, another downside is that while SQL is here to stay, ORMs frameworks can appear and disappear overnight. But overall, I’ve found that ORMs make it much easier to keep track of web application data in Go and reduce the amount of drawn-out coding by switching out a bunch of SQL commands inside my application for something that is easier to work with. 

There are a number of Go ORMs that are being supported and promoted in the community, all available in GoCenter::

  • XORM: A simple and powerful ORM framework for Go
  • Go-PG: A postgreSQL client and ORM for Golang
  • SQLBOILDER: A tool to generate a Go ORM tailored to your database schema
  • SQLX: Not an ORM, but another great tool for SQL in Go

GORM: A Top Gopher

GORM is a developer-friendly ORM created by Jinzhu Zhang and with more than 19,000 stars on GitHub, has great community support and easy to follow documentation. GORM provides CRUD operations and can also be used for the initial migration and creation of the database schema. A few more things that GORM does well includes it’s extendability with native plugin support, it’s reliance on testing, and one-to-one and one-to-many group of associations. Gorm also supports sqlite, mysql, postgres, and mssql.

These features were a big part of why the GORM module is honored as a “Top Gopher” in GoCenter. When you view GoCenter’s rich metadata about the GORM module, you can see why:

 

  • The module’s ReadMe directs you to comprehensive documentation. We can learn more details about the module’s code through the GoDoc tab, which shows automatically generated documentation of functions and more.
  • GoCenter’s Used By and Metrics tabs show that this module is popular and broadly trusted, with many downloads, forks, contributors, and usage by other Go modules.
  • GoCenter’s Security tab also reveals that the current version of this module and its dependencies have no known NVD vulnerabilities, as verified by a JFrog Xray deep scan.

Using GORM

Let’s say you wanted to build an API (or later a web application) that asks users to provide you their name, email address, and a short message. Using GORM, it would be pretty simple set of steps to map this to a database. The steps:

  • Setup your database 
  • Mapping a User struct
  • Connecting to the db
  • Initial migration to db
  • Setting up your functions
  • Running the application

GORM Walkthrough

Let’s say that my part-time real-estate agent (or maybe my sister) needs a web application that can collect and store inquiries about properties that she manages around our hometown. The first thing I would need to do is develop a database that can store user information and a web API that can collect that info through a contact form and later access that user information so it can be read in a browser. We’ll walk through a few of the major steps I took to develop this kind of application.

Importing my Modules

First in our main.go file, we can import our modules with the following commands:

$ export GOPROXY=https://gocenter.io
$ go get github.com/jinzhu/gorm
$ go get github.com/mattn/go-sqlite3

 

DB Connection Variable

Create a simple variable for the GORM database:

var db *gorm.DB

 

User Struct

We’ll create our model definition with a Golang struct that maps the user’s name, their email, and the message. 

// User struct for my db
type User struct {
   gorm.Model
   name    string
   email   string
   message string
}

 

Initial Migration for DB

I’ve named my sqlite database project.db and can use GORM’s AutoMigrate feature with a function that looks like this:

// InitialMigration for project with db.AutoMigrate
func InitialMigration() {
   db, err = gorm.Open("sqlite3", "project.db")
   if err != nil {
       fmt.Println(err.Error())
       panic("Failed to connect to database")
   }
   defer db.Close()
 
   db.AutoMigrate(&User{})
}

 

View Handler Function

This will allow us to see the API data in the browser:

func viewHandler(writer http.ResponseWriter, request *http.Request) {
   placeholder := []byte("Successfully connected to the database...")
   _, err := writer.Write(placeholder)
   check(err)
}

 

API Functionality

The API uses four main functions that will enable us to find/get users, add new users, delete users, and update user information in the db. These can be outlined as:

  • func allUsers
  • func newUser
  • func deleteUser
  • func updateUser

For example, this function will connect to the database and show all entries for users:

func allUsers(w http.ResponseWriter, r *http.Request) {
   db, err := gorm.Open("sqlite3", "project.db")
   if err != nil {
       panic("failed to connect database")
   }
   defer db.Close()
 
   var users []User
   db.Find(&users)
   fmt.Println("{}", users)
 
   json.NewEncoder(w).Encode(users)
}

 

Router

After each function above is created, the function to handle routing would look like this:

func handleRequests() {
   myRouter := mux.NewRouter().StrictSlash(true)
   myRouter.HandleFunc("/users", allUsers).Methods("GET")
   myRouter.HandleFunc("/user/{name}", deleteUser).Methods("DELETE")
   myRouter.HandleFunc("/user/{name}/{email}", updateUser).Methods("PUT")
   myRouter.HandleFunc("/user/{name}/{email}", newUser).Methods("POST")
   myRouter.HandleFunc("/user/{name}/{email}/{message}", updateUser).Methods("PUT")
   myRouter.HandleFunc("/user/{name}/{email}/{message}", newUser).Methods("POST")
   log.Fatal(http.ListenAndServe(":8081", myRouter))
}

 

Main Function

Last, you can run the application by placing the following in your main function:

func main() {
   fmt.Println("GORM API Project Started")
   initialMigration()
   handleRequests()
}

 

Run Application

Then using go run main.go, we’ll see the response:

GORM API Project Started

And when I POST a few requests to my API, I can GET that request and see the data in the browser:

Dive Deeper

As a Go developer using GORM for the first time, it made migration and mapping data to a sqlite database very easy. The code above is just is a snapshot to get you started.

For more information on using GORM to build APIs, check out this excellent full tutorial with video by Elliot Forbes.  Don’t forget to thank Elliot on Twitter for his wonderful tutorial that covers every aspect of Golang APIs. 

GORM v2 is also now published and is being used for public testing. You can checkout GORM v2 here: https://search.gocenter.io/gorm.io/gorm

Conclusion

Go’s strengths in web API development include its speed and scalability; which is pretty important as the era of machine learning becomes mainstream. Go was built in an age of multi-core processors and uses goroutines to thread tasks simultaneously through multiple channels on multiple CPUs. This means it can handle the scale and infrastructure needed for large data applications and can handle millions of HTTP requests simultaneously. It is also statically-typed and its strict syntax makes it much easier to debug and guard against errors that less strict languages with huge libraries like Javascript might introduce. This is why companies from Uber to DropBox are using Go as their language of choice for APIs and to scale their web-enabled applications. 

Should you want to take Go’s API capabilities for a spin, building your own web API using ORMs like GORM are a great place to start.

Checkout GORM on GoCenter or search to discover even more great Go modules.