CRUD REST API with Golang and PostgreSQL Tutorial

by Didin J. on May 12, 2025 CRUD REST API with Golang and PostgreSQL Tutorial

Learn how to build a CRUD REST API using Golang, Fiber, GORM, and PostgreSQL with step-by-step instructions and real code examples


In this tutorial, you’ll learn how to create a fully functional RESTful API using Golang, PostgreSQL, Fiber (a fast Go web framework), and GORM (a powerful ORM library for Go). You’ll perform all basic CRUD operations: Create, Read, Update, and Delete.

CRUD REST API with Golang and PostgreSQL Tutorial - diagram

Prerequisites

Before we start, make sure you have the following:


Step 1: Initialize Go Project

First, create a new folder for your project and initialize it with go mod.

mkdir go-crud-api
cd go-crud-api
go mod init github.com/yourusername/go-crud-api

This sets up a new Go module. Replace yourusername with your actual GitHub username or org name if applicable (eg, "didinj")


Step 2: Install Required Packages

We will use:

  • Fiber for the web framework
  • GORM for ORM/database abstraction
  • PostgreSQL driver for GORM
  • godotenv for loading environment variables

Install them using:

go get github.com/gofiber/fiber/v2
go get gorm.io/gorm
go get gorm.io/driver/postgres
go get github.com/joho/godotenv


Step 3: Configure PostgreSQL and Environment Variables

In another terminal tab, go to the PostgreSQL console.

psql postgres -U djamware

Create a PostgreSQL database manually:

CREATE DATABASE go_crud_db;

Then, create a .env file at the root of your project to securely store database credentials:

DB_HOST=localhost
DB_PORT=5432
DB_USER=djamware
DB_PASSWORD=dj@mw@r3
DB_NAME=go_crud_db

Don't commit .env to version control.


Step 4: Database Connection Setup

Create a new folder called database and inside it a file called database.go.

mkdir database
touch database/database.go

Add the following code:

package database

import (
    "fmt"
    "log"
    "os"

    "gorm.io/gorm"
    "gorm.io/driver/postgres"
    "github.com/joho/godotenv"
)

var DB *gorm.DB

func Connect() {
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading .env file")
    }

    dsn := fmt.Sprintf(
        "host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
        os.Getenv("DB_HOST"),
        os.Getenv("DB_USER"),
        os.Getenv("DB_PASSWORD"),
        os.Getenv("DB_NAME"),
        os.Getenv("DB_PORT"),
    )

    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal("Failed to connect to the database:", err)
    }

    DB = db
    fmt.Println("Database connection established")
}

This file connects to your PostgreSQL database using GORM.


Step 5: Create a Model

Create a models folder and add a file named book.go.

mkdir models
touch models/book.go

Add the following code:

package models

type Book struct {
    ID     uint   `json:"id" gorm:"primaryKey"`
    Title  string `json:"title"`
    Author string `json:"author"`
}

This defines a simple Book model with an ID, Title, and Author. GORM uses this model to create the table automatically.


Step 6: API Routes and Handlers

Create a routes folder and add a file called book.go.

mkdir routes
touch routes/book.go

This file will contain all the CRUD logic:

package routes

import (
    "github.com/didinj/go-crud-api/database"
    "github.com/didinj/go-crud-api/models"

    "github.com/gofiber/fiber/v2"
)

// GET /api/books
func GetBooks(c *fiber.Ctx) error {
    var books []models.Book
    database.DB.Find(&books)
    return c.JSON(books)
}

// GET /api/books/:id
func GetBook(c *fiber.Ctx) error {
    id := c.Params("id")
    var book models.Book
    result := database.DB.First(&book, id)
    if result.Error != nil {
        return c.Status(404).JSON(fiber.Map{"error": "Book not found"})
    }
    return c.JSON(book)
}

// POST /api/books
func CreateBook(c *fiber.Ctx) error {
    book := new(models.Book)
    if err := c.BodyParser(book); err != nil {
        return c.Status(400).JSON(fiber.Map{"error": "Cannot parse JSON"})
    }
    database.DB.Create(&book)
    return c.JSON(book)
}

// PUT /api/books/:id
func UpdateBook(c *fiber.Ctx) error {
    id := c.Params("id")
    var book models.Book
    if err := database.DB.First(&book, id).Error; err != nil {
        return c.Status(404).JSON(fiber.Map{"error": "Book not found"})
    }

    if err := c.BodyParser(&book); err != nil {
        return c.Status(400).JSON(fiber.Map{"error": "Cannot parse JSON"})
    }

    database.DB.Save(&book)
    return c.JSON(book)
}

// DELETE /api/books/:id
func DeleteBook(c *fiber.Ctx) error {
    id := c.Params("id")
    result := database.DB.Delete(&models.Book{}, id)
    if result.RowsAffected == 0 {
        return c.Status(404).JSON(fiber.Map{"error": "Book not found"})
    }
    return c.JSON(fiber.Map{"message": "Book deleted successfully"})
}

func SetupRoutes(app *fiber.App) {
    api := app.Group("/api")
    books := api.Group("/books")

    books.Get("/", GetBooks)
    books.Get("/:id", GetBook)
    books.Post("/", CreateBook)
    books.Put("/:id", UpdateBook)
    books.Delete("/:id", DeleteBook)
}

    books.Get("/", GetBooks)
    books.Get("/:id", GetBook)
    books.Post("/", CreateBook)
    books.Put("/:id", UpdateBook)
    books.Delete("/:id", DeleteBook)
}

These handlers manage the lifecycle of book records through RESTful routes.


Step 7: Main Application Entry Point

Now create the main.go the file at the root:

package main

import (
    "github.com/didinj/go-crud-api/database"
    "github.com/didinj/go-crud-api/models"
    "github.com/didinj/go-crud-api/routes"

    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()

    // Connect to DB
    database.Connect()

    // Auto-migrate Book model to create the table
    database.DB.AutoMigrate(&models.Book{})

    // Setup API routes
    routes.SetupRoutes(app)

    // Start the server
    app.Listen(":3000")
}


Step 8: Run the Application

Now you can run your app with:

go run main.go

If successful, you should see:

Database connection established

 ┌───────────────────────────────────────────────────┐ 
 │                   Fiber v2.52.6                   │ 
 │               http://127.0.0.1:3000               │ 
 │       (bound on host 0.0.0.0 and port 3000)       │ 
 │                                                   │ 
 │ Handlers ............. 7  Processes ........... 1 │ 
 │ Prefork ....... Disabled  PID .............. 4390 │ 
 └───────────────────────────────────────────────────┘ 

Visit: http://localhost:3000/api/books


Step 9: Test the API

Use curl or Postman to test:

Create a Book

curl -X POST http://localhost:3000/api/books \
-H "Content-Type: application/json" \
-d '{"title":"The Go Programming Language","author":"Alan Donovan"}'

Response:

{"id":1,"title":"The Go Programming Language","author":"Alan Donovan"}

📚 Get All Books

curl http://localhost:3000/api/books

Response:

[{"id":1,"title":"The Go Programming Language","author":"Alan Donovan"}]

🔍 Get Book by ID

curl http://localhost:3000/api/books/1

Response:

{"id":1,"title":"The Go Programming Language","author":"Alan Donovan"}

✏️ Update a Book

curl -X PUT http://localhost:3000/api/books/1 \
-H "Content-Type: application/json" \
-d '{"title":"Go in Action","author":"William Kennedy"}'

Response:

{"id":1,"title":"Go in Action","author":"William Kennedy"}

🗑 Delete a Book

curl -X DELETE http://localhost:3000/api/books/1

Response:

{"message":"Book deleted successfully"}


Conclusion

You’ve successfully built a Golang CRUD REST API backed by PostgreSQL, with Fiber for routing and GORM for ORM/database interactions.

This setup provides a great foundation for building microservices, modern backends, or full-stack apps with React, Vue, or Angular as a frontend.

You can find the working source code on our GitHub.

That is just the basics. If you need more deep learning about the Golang (Go) language and frameworks, you can take the following cheap course:

  • Collaboration and Crawling W/ Golang - Google's Go Language
  • How to Build a Golang Blog Engine Web Application
  • Fundamentals of Go Learn GoLang Programming Language
  • How to Build 1 Million Requests per Minute with Golang
  • The Complete React & Golang Course

Thanks!