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.
Prerequisites
Before we start, make sure you have the following:
- Go installed (recommended v1.20 or newer): https://golang.org/dl
- PostgreSQL is installed and running: https://www.postgresql.org/download/
- Familiarity with Go basics
- A REST API testing tool (e.g., Postman or curl)
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's just the basics. If you need more deep learning about Go/Golang, you can take the following cheap course:
- Go - The Complete Guide
- NEW-Comprehensive Go Bootcamp with gRPC and Protocol Buffers
- Backend Master Class [Golang + Postgres + Kubernetes + gRPC]
- Complete Microservices with Go
- Backend Engineering with Go
- Introduction to AI and Machine Learning with Go (Golang)
- Working with Concurrency in Go (Golang)
- Introduction to Testing in Go (Golang)
- Design Patterns in Go
- Go Bootcamp: Master Golang with 1000+ Exercises and Projects
Thanks!