How to Build an Enterprise‑Grade API with Gin and GORM
This tutorial walks through creating a complete Go backend service using Gin and GORM, covering project setup, layered architecture, database initialization, user model definition, JWT‑based registration and login, pagination, middleware, routing, and deployment options, while also suggesting extensible features such as RBAC, Swagger, Redis caching, Docker, and micro‑service frameworks.
Project Goal
Implement a user‑management API with features including registration, JWT login, paginated user listing, and placeholders for permission management.
Technology Stack
Gin (web framework) + GORM (ORM) + Viper (configuration) + Zap (logging) + golang‑jwt (JWT handling) + MySQL driver.
Project Structure
go-gin-api/
├── config/ # configuration
├── controller/ # controller layer
├── middleware/ # middleware
├── model/ # data models
├── router/ # route registration
├── service/ # business logic
├── utils/ # utility functions
├── main.go # program entry
└── go.modThe author strongly recommends a layered architecture (Controller → Service → Model) to facilitate unit testing and future extensions.
Environment Initialization
Initialize Go module: go mod init go-gin-api Install dependencies:
go get -u github.com/gin-gonic/gin
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
go get -u github.com/spf13/viper
go get -u go.uber.org/zap
go get -u github.com/golang-jwt/jwt/v5Database Configuration & GORM Initialization
// config/database.go
package config
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
)
var DB *gorm.DB
func InitDB() {
dsn := "root:password@tcp(127.0.0.1:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
}Data Model Definition (User)
// model/user.go
package model
import "gorm.io/gorm"
type User struct {
gorm.Model
Username string `gorm:"unique"`
Password string
Email string
}Registration & Login Endpoints (JWT Authentication)
Registration
// controller/user.go
func Register(c *gin.Context) {
var user model.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"msg": "Invalid parameters"})
return
}
// Password hashing can be done with bcrypt
if err := config.DB.Create(&user).Error; err != nil {
c.JSON(500, gin.H{"msg": "Registration failed"})
return
}
c.JSON(200, gin.H{"msg": "Registration successful"})
}Login (Issue JWT)
func Login(c *gin.Context) {
var input model.User
var user model.User
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(400, gin.H{"msg": "Invalid parameters"})
return
}
config.DB.Where("username = ? AND password = ?", input.Username, input.Password).First(&user)
if user.ID == 0 {
c.JSON(401, gin.H{"msg": "Incorrect username or password"})
return
}
token, _ := utils.GenerateToken(user.Username) // custom JWT generation
c.JSON(200, gin.H{"token": token})
}Paginated Query Example
func ListUsers(c *gin.Context) {
var users []model.User
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize := 10
offset := (page - 1) * pageSize
config.DB.Offset(offset).Limit(pageSize).Find(&users)
c.JSON(200, users)
}JWT Authentication Middleware
func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenStr := c.GetHeader("Authorization")
claims, err := utils.ParseToken(tokenStr)
if err != nil {
c.AbortWithStatusJSON(401, gin.H{"msg": "Unauthenticated or invalid token"})
return
}
c.Set("username", claims.Username)
c.Next()
}
}Router Registration
// router/router.go
func InitRouter() *gin.Engine {
r := gin.Default()
r.POST("/register", controller.Register)
r.POST("/login", controller.Login)
auth := r.Group("/api", middleware.JWTAuthMiddleware())
{
auth.GET("/users", controller.ListUsers)
// other CRUD endpoints
}
return r
}Start the Application
// main.go
func main() {
config.InitDB()
r := router.InitRouter()
r.Run(":8080")
}Running the Service
Use tools like Postman or curl to test the endpoints:
POST /register – user registration
POST /login – obtain JWT token
GET /api/users – retrieve paginated user list with JWT authentication
Potential Extensions
Integrate Casbin for RBAC permission management
Add Swagger to generate API documentation
Use Redis for caching and rate limiting
Package the application into a Docker image and deploy to Kubernetes
Adopt go‑zero to build a micro‑service architecture
What You Will Gain
Complete development workflow for Gin + GORM
Understanding of layered architecture for maintainable code
Practical experience with JWT authentication, pagination, and hot reload
A ready‑to‑extend Golang backend project template
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Golang Shines
We share daily the latest Golang technical articles, practical resources, language news, tutorials, and real-world projects to help everyone learn and improve.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
