CRUD API using GO, GIN, MySql

Thinley Norbu
Aug 18, 2020 · 3 min read

GO has been around for a quite long time now. It is considered as one of the fastest programming language with high performance. In this article, I will be sharing how I wrote CRUD API using GO. Technologies used in this article are GO, Gin, GORM and Mysql.

Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks to httprouter.

GORM is a ORM library for GOlang.

I am providing the github link to the repository for this article.

So let’s start writing CRUD API now. Create a new GO project and install the related dependencies. We install GORM, Gin and Mysql by running following commands.

go get github.com/go-sql-driver/mysql
go get github.com/gin-gonic/gin
go get github.com/jinzhu/gorm

For setting up our Mysql database. We can add the following piece of code.

package modelsimport (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/gorm"
)
// SetupDB : initializing mysql databasefunc SetupDB() *gorm.DB {
USER := "root"
PASS := "password"
HOST := "localhost"
PORT := "3306"
DBNAME := "bookCRUD"
URL := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", USER, PASS, HOST, PORT, DBNAME)
db, err := gorm.Open("mysql", URL)if err != nil {
panic(err.Error())
}
return db}

For the sake of simplicity, I have left the user ,password and other credentials hard coded. You can load it from env file too. We connect to mysql using the gorm.Open.

Now we create our first model. We can create our model by using following code.

// models/book.go
package models
type Task struct {ID uint `json:"id" gorm:"primary_key"`AssingedTo string `json:"assignedTo"`Task string `json:"task"`}

Nothing much here, we just have id, assigedto and task field. Id is unique int whereas assignedto and task are strings.

Now,we move towards configuring our routes for the API. Generally, we make a separate file for routes but to keep it short, I have added the routes in the main.go file. It can look something like this.

package mainimport (
"bookCRUD/controllers"
"bookCRUD/models"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
db := models.SetupDB()
db.AutoMigrate(&models.Task{})
r.Use(func(c *gin.Context) {
c.Set("db", db)
})
r.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"data": "hello world"})
})
r.GET("/tasks", controllers.FindTasks)
r.POST("/tasks", controllers.CreateTask)
r.GET("/tasks/:id", controllers.FindTask)
r.PATCH("/tasks/:id", controllers.UpdateTask)
r.DELETE("tasks/:id", controllers.DeleteTask)
r.Run()
}

We can now make controllers that handles the request on the routes configured. The controllers file can be something like this.

// controllers/books.gopackage controllersimport (// "bookc/models"
"bookCRUD/models"
"net/http"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
)type CreateTaskInput struct {
AssingedTo string `json:"assignedTo"`
Task string `json:"task"`
}
type UpdateTaskInput struct {
AssingedTo string `json:"assignedTo"`
Task string `json:"task"`
}
// GET /tasks// Get all tasks
func FindTasks(c *gin.Context) {
db := c.MustGet("db").(*gorm.DB)
var tasks []models.Task
db.Find(&tasks)
c.JSON(http.StatusOK, gin.H{"data": tasks})
}
// POST /tasks// Create new taskfunc CreateTask(c *gin.Context) {
// Validate input
var input CreateTaskInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Create tasktask := models.Task{AssingedTo: input.AssingedTo, Task: input.Task}
db := c.MustGet("db").(*gorm.DB)
db.Create(&task)
c.JSON(http.StatusOK, gin.H{"data": task})
}
// GET /tasks/:id// Find a taskfunc FindTask(c *gin.Context) { // Get model if exist
var task models.Task
db := c.MustGet("db").(*gorm.DB)
if err := db.Where("id = ?", c.Param("id")).First(&task).Error; err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
return
}
c.JSON(http.StatusOK, gin.H{"data": task})}// PATCH /tasks/:id// Update a taskfunc UpdateTask(c *gin.Context) {db := c.MustGet("db").(*gorm.DB)// Get model if existvar task models.Taskif err := db.Where("id = ?", c.Param("id")).First(&task).Error; err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})return}// Validate input
var input UpdateTaskInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
db.Model(&task).Updates(input)c.JSON(http.StatusOK, gin.H{"data": task})
}
// DELETE /tasks/:id// Delete a taskfunc DeleteTask(c *gin.Context) {
// Get model if exist
db := c.MustGet("db").(*gorm.DB)
var book models.Task
if err := db.Where("id = ?", c.Param("id")).First(&book).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
return
}
db.Delete(&book)c.JSON(http.StatusOK, gin.H{"data": true})}

Now we are ready to run our server and try out what we have created so far.

Run

go run main.go

We can try to access the end point described in our main.go file. It must return required values.

This is a very simple API example. By using this foundation, we can now continue creating more complex APIs.

Download repo here.

wesionaryTEAM

Visionary Development Team. We ❤︎ Technology!