Logo

dev-resources.site

for different kinds of informations.

🚀 Building a RESTful API in Go: A Practical Guide

Published at
1/5/2025
Categories
restapi
go
gin
postgres
Author
chamupathi_mendis_cdd19da
Categories
4 categories in total
restapi
open
go
open
gin
open
postgres
open
Author
25 person written this
chamupathi_mendis_cdd19da
open
🚀 Building a RESTful API in Go: A Practical Guide

From Setup to CRUD Operations with Gin & PostgreSQL

Golang is a fantastic programming language! If you're just starting out, the official documentation is a great resource. But when it comes to practical application, things can get tricky.

Many developers have asked me how to build a RESTful API using Go, so I decided to create a minimal working REST API with step-by-step guidance. Let's dive in! 🔥


🛠 Step-by-Step Guide to Building a REST API in Go
We'll be using:
✅ Gin (Fast & lightweight web framework)
✅ GORM (ORM for PostgreSQL)
✅ Docker (To run PostgreSQL in a container)


Step 1: Setting Up the Project & Installing Dependencies

First, create a new Go project:

mkdir go-rest-api && cd booking-app
go mod init booking-app
Enter fullscreen mode Exit fullscreen mode

Next, install Gin:

go get -u github.com/gin-gonic/gin
Enter fullscreen mode Exit fullscreen mode

Create the initial route

create file routes/booking.go

package routes

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func GetBookings(c *gin.Context) {
    var bookings []string = []string{"abc"}
    c.JSON(http.StatusOK, bookings)
}

func SetupRoutes(router *gin.Engine) {
    router.GET("v1/bookings", GetBookings)
}
Enter fullscreen mode Exit fullscreen mode

To use above route in main.go, create a file main.go

package main

import (
    "booking-app/routes"
    "fmt"

    "github.com/gin-gonic/gin"
)

func main() {
    // Setup Gin Router
    router := gin.Default()

    routes.SetupRoutes(router)

    // Start the server
    port := ":8080"
    fmt.Println("Server is running on port", port)
    router.Run(port)
}
Enter fullscreen mode Exit fullscreen mode

run

go run main.go
Enter fullscreen mode Exit fullscreen mode

visit http://localhost:8080/v1/bookings you should get a response with ["abc"]

Step 2: Setting Up PostgreSQL Using Docker:

Instead of installing PostgreSQL manually, let's use Docker.

To make sure that the starting docker container lives with the application itself, let create a docker-compose

docker-compose.yml

version: '3.8'

services:
  postgres:
    image: postgres:latest
    container_name: postgres_container
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: yourpassword
      POSTGRES_DB: booking_db
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
Enter fullscreen mode Exit fullscreen mode

run

docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

make sure that the docker is running in background

adding DB connectivity to the app

create the file config/database.go

package config

import (
    "fmt"
    "log"

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

var DB *gorm.DB

func ConnnetDatabse() {
    dsn := "host=localhost user=postgres password=yourpassword dbname=booking_db port=5432 sslmode=disable"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

    if err != nil {
        // log.Fatal will log the message to terminal and exit the program
        log.Fatal("Failed to connect to the database:", err)
    }

    DB = db

    fmt.Println("Connected to PostgreSQL!")
}
Enter fullscreen mode Exit fullscreen mode

add following line at the top of the function main in main.go to initialise the database connection.

    config.ConnnetDatabse()
Enter fullscreen mode Exit fullscreen mode

The step 2 github link

Step 3: Adding a Data Model & First Route (Create a Resource)

Let's define a model for our API.

First, install GORM and the PostgreSQL driver:

go get -u gorm.io/gorm
go get -u gorm.io/driver/postgres
Enter fullscreen mode Exit fullscreen mode

create the modal

package models

import "gorm.io/gorm"

type User struct {
    gorm.Model
    Name  string `json:"name" binding:"required" gorm:"not null"`
    Email string `json:"email" binding:"required,email" gorm:"not null"`
    Date  string `json:"date"`
}
Enter fullscreen mode Exit fullscreen mode

gorm.Modal adds few default fields to the struct as ID, CreatedAt, UpdatedAt, DeletedAt and managed by it self.

bindind make sure that the fileds are validate when the json is binded to the modal.

lets create a controller to for bookings

controller/bookings.go

package controllers

import (
    "booking-app/config"
    "booking-app/models"
    "net/http"

    "github.com/gin-gonic/gin"
)

func GetBookings(c *gin.Context) {
    var bookings []models.Booking
    config.DB.Find(&bookings)
    c.JSON(http.StatusOK, bookings)
}

func CreateBooking(c *gin.Context) {
    var booking models.Booking

    if err := c.ShouldBindJSON(&booking); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    config.DB.Create(&booking)
    c.JSON(http.StatusCreated, booking)
}
Enter fullscreen mode Exit fullscreen mode

We have created a handler for creating bookings and moved the logic to get bookings from routes file as well.

now update the routes/booking.go as well.

package routes

import (
    "booking-app/controllers"

    "github.com/gin-gonic/gin"
)

func SetupRoutes(router *gin.Engine) {
    router.GET("v1/bookings", controllers.GetBookings)
    router.POST("v1/bookings", controllers.CreateBooking)
}
Enter fullscreen mode Exit fullscreen mode

now let's test the endpoint

curl -X POST http://localhost:8080/v1/bookings -H "Content-Type: application/json" -d '{"name":"John Doe", "email":"[email protected]"}'

Enter fullscreen mode Exit fullscreen mode

code for step 3

Step 4: Get a booking by ID

Lets update the controller to get a booking

func GetBookingsById(c *gin.Context) {
    id := c.Param("id")

    var booking models.Booking

    err := config.DB.First(&booking, id).Error
    if err != nil {
        c.JSON(http.StatusNotFound, nil)
        return
    }

    c.JSON(http.StatusOK, booking)
}
Enter fullscreen mode Exit fullscreen mode

lets add the route to routes/booking.go

router.GET("v1/bookings/:id", controllers.GetBookingsById)
Enter fullscreen mode Exit fullscreen mode

By re-running the application you should be able to fetch booking by id

code for step 04

Step 5: Update & Delete Operations

now you guessed right. know the drill. update the controller, ad it to route.

controllers/booking.go

type UpdateBookingRequest struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Date  string `json:"date"`
}

func UpdateBooking(c *gin.Context) {
    var id = c.Param("id")
    var booking models.Booking
    var updateRequest UpdateBookingRequest

    err := config.DB.First(&booking, id)

    if err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Booking not found"})
    }

    if err := c.ShouldBindJSON(&updateRequest); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    if err := config.DB.Model(&booking).Updates(updateRequest).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"})
        return
    }

    c.JSON(http.StatusOK, booking)
}

func DeleteBooking(c *gin.Context) {
    var id = c.Param("id")
    var booking models.Booking

    if err := config.DB.First(&booking, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "Booking not found"})
        return
    }

    if err := config.DB.Delete(&booking).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"})
        return
    }

    c.JSON(http.StatusOK, booking)
}
Enter fullscreen mode Exit fullscreen mode

wait, there is a new struct for updates, Yes. that's because we have already added validations for bookings modal as both name and email are required, but for an update we might only need to update one of it not both. other than that this enables adding custom validations only for update request if needed.

routes/booking.go

    router.PUT("v1/bookings/:id", controllers.UpdateBooking)
    router.DELETE("v1/bookings/:id", controllers.DeleteBooking)
Enter fullscreen mode Exit fullscreen mode

here is the code after adding delete and update operations.


🎉 Conclusion

Congratulations! You’ve built a fully functional RESTful API in Go with: ✅ Gin for routing

✅ PostgreSQL (via Docker) for storage
✅ GORM for database interactions
✅ CRUD operations


Hope you enjoyed this guide! Let me know your thoughts in the comments. 🚀

gin Article's
30 articles in total
Favicon
Developing a Simple RESTful API with Gin, ginvalidator, and validatorgo
Favicon
Go's Concurrency Decoded: Goroutine Scheduling
Favicon
🚀 Building a RESTful API in Go: A Practical Guide
Favicon
A Deep Dive into Gin: Golang's Leading Framework
Favicon
Building a Blog API with Gin, FerretDB, and oapi-codegen
Favicon
How to enable hot reload in your Gin project
Favicon
Implementing an Order Processing System: Part 1 - Setting Up the Foundation
Favicon
Gin and router example
Favicon
How to Upload Images to AWS S3 with Golang
Favicon
Basic CRUD Operations Using Golang, Gin Gonic, and GORM
Favicon
Simplifying User Management with GIN and MongoDB
Favicon
Gin + Gorm Practical Guide, Implementing a Simple Q&A Community Backend Service in One Hour
Favicon
A Beginner-friendly Approach to Developing a REST API with Go, Gin and MSQL
Favicon
Cara menggunakan Cobra untuk menjalankan server Golang Gin
Favicon
A Beginner-friendly Approach to Developing a REST API with Go and Gin
Favicon
Easily build a simple and reliable ordering system in an hour using go efficiency tools
Favicon
Example 5, Automatically generate grpc gateway service project code, easy to achieve cross-service grpc calls
Favicon
Example 3, Automatically generate generic web service (gin) project code, increasing development efficiency by at least 1x
Favicon
Example 6, Build a simple golang e-commerce microservices framework step by step using tool
Favicon
Building a simple API with Golang using Gin-gonic
Favicon
Golang Web API: Project configuration management using Viper
Favicon
Golang Web API Course: Create starter project with a simple health check endpoint
Favicon
API validation in Gin: Ensuring Data Integrity in Your API
Favicon
Using the tool to complete the conversion of a community back-end single service to a microservice cluster in one day
Favicon
A secret weapon to improve the efficiency of golang development, a community backend service was developed in one day
Favicon
Play Microservices: Api-gateway service
Favicon
Set up a Stripe Checkout REST API (+ metadata) using Go and Gin Framework.
Favicon
Go: CRUD API using Gin Framework
Favicon
Example 1, Automatically generate a complete gin+gorm+redis+CRUD web service project without writing a line of Go code
Favicon
Not a Go LiveView developer yet? Try to guess what this code is doing, though.

Featured ones: