Categorygithub.com/landofcoder/go-lang-gin-postgresql-example
modulepackage
0.0.0-20250120014142-c9544fe4ed9d
Repository: https://github.com/landofcoder/go-lang-gin-postgresql-example.git
Documentation: pkg.go.dev

# README

go-lang-gin-postgresql-example

Deploying a Golang RESTful API with Go using Gin, Gorm and PostgreSQL - Example use Gin and Postgre Sql

In this tutorial, we’ll demonstrate how to build a bookstore REST API that provides book data and performs CRUD operations.

Before we get begin, I’ll assume that you:

  • Have Go installed on your machine
  • Understand the basics of Go language
  • Have a general understanding of RESTful API

Installation

Let’s start by initializing a new Go module to manage our project’s dependencies. Make sure you run this command inside your Go environment folder:

go run main.go

Now let’s install Gin and Gorm packages:

go get github.com/gin-gonic/gin gorm.io/gorm gorm.io/driver/postgres go get github.com/joho/godotenv

Setting up the server

Let’s start by creating a Hello World server inside the main.go file:

package main

import (
  "net/http"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()

  r.GET("/", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"data": "hello world"})    
  })

  r.Run()
}

To test it out, we’ll start our server by running the command below: go run main.go

Setting up the database

The next thing we need to do is to build our database models.

Model is a class (or structs in Go) that allows us to communicate with a specific table in our database. In Gorm, we can create our models by defining a Go struct. This model will contain the properties that represent fields in our database table. Since we’re trying to build a bookstore API, let’s create a Book model:

\\models\contact.go
package models

type Contact struct {
	ID          uint   `json:"id" gorm:"primary_key"`
	FirstName   string `json:"first_name"`
	LastName    string `json:"last_name"`
	PhoneNumber string `json:"phone_number"`
	Email       string `json:"email" gorm:"unique"`
	Address     string `json:"address"`
	City        string `json:"city"`
	State       string `json:"state"`
	ZipCode     string `json:"zip_code"`
	Country     string `json:"country"`
	Tags        string `json:"tags"`
	CreatedAt   string `json:"created_at"`
	UpdatedAt   string `json:"updated_at"`
}

type CreateContactInput struct {
	FirstName   string `json:"first_name" binding:"required"`
	LastName    string `json:"last_name" binding:"required"`
	PhoneNumber string `json:"phone_number"`
	Email       string `json:"email" binding:"required"`
	Address     string `json:"address"`
	City        string `json:"City"`
	State       string `json:"state"`
	ZipCode     string `json:"zip_code"`
	Country     string `json:"country"`
	Tags        string `json:"tags"`
}

type struct UpdateContactInput {
	FirstName  string `json:"fist_name" binding:"required"`
	LastName string `json:"last_name" binding:"required"`
	PhoneNumber string `json:"phone_number"`
	Address string `json:"address"`
	City string `json:"City"`
	State string `json:"state"`
	ZipCode string `json:"zip_code"`
	Country string `json:"country"`
	Tags string `json:"tags"`
}

Next, we need to create a utility function called ConnectDatabase that allows us to create a connection to the database and migrate our model’s schema. We can put this inside the setup.go file in our models module:

// models/setup.go

package models

import (
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

var DB *gorm.DB

func ConnectDatabase() {

	dsn := "host=localhost user=root password=simplecrm2024 dbname=crm_db port=5432 sslmode=disable TimeZone=Asia/Shanghai"
	database, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

	if err != nil {
		panic("Failed to connect to database!")
	}

	err = database.AutoMigrate(&Contact{})
	if err != nil {
		return
	}

	DB = database
}

In main.go, we need to call the following function before we run our app:

package main

import (
  "github.com/gin-gonic/gin"

  "github.com/landofcoder/go-lang-gin-postgresql-example/models" // new
)

func main() {
  r := gin.Default()

  models.ConnectDatabase() // new

  r.Run()
}

Setting up the RESTful routes

We’re almost there!

The last thing we need to do is to implement our controllers. In the previous section, we learned how to create a route handler (i.e., controller) inside our main.go file. However, this approach makes our code much harder to maintain. Instead of doing that, we can put our controllers inside a separate module called controllers. file: controllers\contact.go with there functions:

  • The Read handler function
  • The Create handler function
  • The Create handler function for single data
  • The Update handler function
  • The Delete handler function

Demo Data

  • run endpoint: /contacts Return data:
{
  "data": []
}
  • send a POST request to /contacts endpoint with this request body:
{
  "first_name": "Thuan",
  "last_name": "Luu",
  "phone_number": "+84 866360623",
  "email": "[email protected]",
  "company": "landofcoder",
  "job_title": "Engineering",
  "address": "No 36, TT03 Moncity, Nam Tu Liem",
  "city": "Ha Noi",
  "state": "Hanoi",
  "zip_code": "100000",
  "country": "Vietnam",
  "tags": "An Entrepreneur,Software Engineer,Saas,Golang,Reactjs,Magento,Shopify,Woocommerce,Wordpress"
}

The response should look like this:

{
  "data": {
    "id": 1,
    "first_name": "Thuan",
    "last_name": "Luu",
    ...
  }
}
  • Let’s run the server and fetch /contacts/1 to get the book we just created:
{
  "data": {
    "id": 1,
    "first_name": "Thuan",
    "last_name": "Luu",
    ...
  }
}
  • Let’s test it out! Fire a PATCH request to the /contacts/:id endpoint to update the book title:
{
  "company": "Bavaan"
}

The result should be as follows:

{
  "data": {
    "id": 1,
    "first_name": "Thuan",
    "last_name": "Luu",
    "company": "Bavaan",
    ...
  }
}
  • Let’s test it out by sending a DELETE request to the /contacts/1 endpoint:
{
  "data": true
}

If we fetch all books in /contacts, we’ll see an empty array again:

{
  "data": []
}

# Packages

No description provided by the author
No description provided by the author