Today I’m going to try build Docker containers for a URL shortener application named Uturn-Go. Credits to Anirudh Rowjee for the Go application.
https://github.com/anirudhRowjee/uturn-go#
This was surprisingly pretty straightforward .The application - main.go:
package main
import (
"fmt"
"math/rand"
"time"
"github.com/gin-gonic/gin"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// Jo: Creating a data structure to hold the URL and Shortcode (if we were using Redis it'd be the Key:Value)
type UrlStruct struct {
gorm.Model
Shortcode string `json:"shortcode"`
URL string `json:"url"`
}
var shortcode_sample_space = []rune("abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMOPQRSTUVWXYZ0123456789")
var shortcode_sample_space_length = len(shortcode_sample_space)
func generate_random_shortcode(length int) string {
new_shortcode := make([]rune, length)
for i := range new_shortcode {
new_shortcode[i] = shortcode_sample_space[rand.Int63n(int64(shortcode_sample_space_length))]
}
return string(new_shortcode)
}
func main() {
// seed the random number generator
rand.Seed(time.Now().UnixNano())
fmt.Println("Random text >> ", generate_random_shortcode(10))
// Test static data
var store_static = []UrlStruct{
{Shortcode: "abc", URL: "<https://www.google.com>"},
{Shortcode: "def", URL: "<https://www.amazon.com>"},
{Shortcode: "ghi", URL: "<https://www.twitter.com>"},
{Shortcode: "lmno", URL: "<https://www.facebook.com>"},
}
fmt.Println(len(store_static))
// Adding database connectivity
// Jo: Using SQLite as the database for this example
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("Could not open Database!")
}
// Automigrate the schema
db.AutoMigrate(&UrlStruct{})
// Jo: Starting a new Gin router
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.GET("/urls", func(c *gin.Context) {
// get all the URLs in JSON.
var results []UrlStruct
db.Find(&results)
c.JSON(200, results)
})
r.POST("/urls", func(c *gin.Context) {
var currentUrl UrlStruct
// parse request body to get the proposed URL Object
//Jo: We're taking the input body parameters and binding them to the new struct
if err := c.BindJSON(¤tUrl); err != nil {
fmt.Println("Error ! Could not read JSON Formatting!")
c.JSON(400, gin.H{
"Error": "Improperly shaped JSON request body",
})
}
//Jo: Generate shortcode for the URL
if currentUrl.Shortcode == "" {
currentUrl.Shortcode = generate_random_shortcode(5)
}
// insert this into the database
result := db.Create(¤tUrl)
if result.Error != nil {
c.JSON(400, gin.H{
"Error": "Could not insert into database",
"Reason": result.Error,
})
}
// send a success confirmation
c.JSON(200, currentUrl)
})
r.GET("/:shortcode", func(c *gin.Context) {
// get the shortcode from the URL Body
shortcode, success := c.Params.Get("shortcode")
if success == false {
c.JSON(404, gin.H{
"Error": "Could not parse URL",
})
}
// fetch the shortcode from the database
current_url := UrlStruct{Shortcode: shortcode}
db.Where("shortcode = ?", shortcode).First(¤t_url)
fmt.Println("Current URL Fetched: ", current_url)
// send a redirect to there
c.Redirect(301, current_url.URL)
})
r.Run(":8000")
}
<aside>
[]rune → its an alias for int32 OR a 32 bit long data type used to store Unicode code points (wider range than ASCII, including emojis, etc.)
</aside>
<aside>
GORM is a ORM(Object Relational Mapper) in Go. Helps you work with SQLite databases. Gin is a web framework allowing you to create REST APIs for the application (https://echo.labstack.com/ is an alternative to Gin)
</aside>
<aside>
fmt is to print to console.
</aside>

I ran the POST request using Postman and tada! I can access the url at https://localhost:8000/sTi2Q

Little bit about the database- SQLite

General steps to build a Dockerfile