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 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!