برنامه نویس فان | Fun Developer یک آدم ساده که عاشق برنامه نویسی و کد زدنه :) تلاش میکنه تا به بقیه کمک کنه. توسعه دهنده هسته لاراول و فضای اوپن سورس. فاندر پرانتز و کد نیوز.

در این مقاله به آموزش ساخت یک RESTful API در زبان برنامهنویسی Go (گولنگ) با استفاده از فریمورک قدرتمند Gin، کتابخانه ORM محبوب Gorm و سیستم کش Redis میپردازیم. هدف این آموزش، ساخت یک API سریع، مقیاسپذیر و بهینه است که بتواند بهصورت مؤثر با پایگاهداده ارتباط برقرار کند و همزمان با استفاده از Redis عملکرد بهتری ارائه دهد. با دنبال کردن این آموزش، با نحوه پیادهسازی ساختار پایه API، اتصال به دیتابیس، انجام عملیات CRUD و استفاده از کش Redis آشنا خواهید شد.
مرور کلی
- Gin: یک فریم ورک وب HTTP با عملکرد بالا در زبان گو است که برای ساخت APIهای RESTful بسیار مناسب است.
- Gorm: یک ORM برای زبان گولنگ است که رابطی سطح بالا برای کار با پایگاهداده فراهم میکند.
- Redis: بهعنوان لایه کش مورد استفاده قرار میگیرد تا با ذخیرهسازی دادههای پرکاربرد در حافظه، بار روی پایگاهداده را کاهش دهد.
عملیات هایی که انجام میدیم امروز
-
راهاندازی یک ساختار پایه برای API با استفاده از Gin
-
اتصال به پایگاهداده و انجام عملیات CRUD با Gorm
-
افزودن کش Redis برای بهبود عملکرد API
پیشنیازها
-
نصب بودن زبان گولنگ (Golang)
-
نصب بودن ردیس (Redis)
-
نصب دیتابیسPostgreSQL یا MySQL
ساختار پروژه
codenews/
├── main.go
├── config/
│ ├── config.go
│ └── database.go
├── controllers/
│ └── user_controller.go
├── models/
│ └── user.go
├── repositories/
│ └── user_repository.go
├── services/
│ └── user_service.go
├── cache/
│ └── redis.go
└── routes/
└── routes.go
1. راه اندازی کانفیگ
یک فایل در مسیر config/config.go
ایجاد کنید. این فایل قراره کانفیگ اپلیکیشن ما باشه و تمامی کانفیگ ها در این فایل قرار میگیره:
package config
import (
"fmt"
"os"
"github.com/joho/godotenv"
)
type Config struct {
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
RedisAddr string
RedisPassword string
RedisDB int
}
var AppConfig *Config
func LoadConfig() {
if err := godotenv.Load(); err != nil {
fmt.Println("No .env file found")
}
AppConfig = &Config{
DBHost: os.Getenv("DB_HOST"),
DBPort: os.Getenv("DB_PORT"),
DBUser: os.Getenv("DB_USER"),
DBPassword: os.Getenv("DB_PASSWORD"),
DBName: os.Getenv("DB_NAME"),
RedisAddr: os.Getenv("REDIS_ADDR"),
RedisPassword: os.Getenv("REDIS_PASSWORD"),
RedisDB: 0,
}
}
در اینجا ما کانفیگ های دیتابیس و ردیس ست کردیم. شما در فایل .env
خودتون این مقادیر رو میتونید پر کنید.
در اینجا ما از پکیج godotenv استفاده کردیم، شما میتونید با استفاده از go mod tidy بیاید این پکیج ها نصب کنید یا دستی خودتون مستقیم نصب کنید و این موارد من در این پست دیگه اشاره نمیکنم، چون اصولا خودتون بلد هستید🤟
2. اتصال به دیتابیس با استفاده از Gorm
برای اتصال به دیتابیس ما یک فایل در مسیر config/database.go
ایجاد میکنیم. در اینجا عملیات وصل شدن به دیتابیس با استفاده از Gorm انجام میدیم:
package config
import (
"fmt"
"log"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var DB *gorm.DB
func ConnectDatabase() {
var err error
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
AppConfig.DBHost, AppConfig.DBUser, AppConfig.DBPassword, AppConfig.DBName, AppConfig.DBPort)
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database!", err)
}
log.Println("Database connected")
}
در اینجا با استفاده از فایل کانفیگ که در قسمت 1 ایجاد کردیم، اومدیم از کانفیگ دیتابیس استفاده کردیم و همینطور یک متغیر Global
ایجاد کردیم به نام DB
که به دیتابیس دسترسی داشته باشیم در کل اپلیکیشن.
3. راه اندازی کش با استفاده از ردیس (Redis)
برای راه اندازی کش در اپلیکیشن یک فایل در مسیر cache/redis.go
ایجاد میکنیم تا بتونیم ردیس رو راه اندازی کنیم:
package cache
import (
"context"
"github.com/redis/go-redis/v9"
"myapp/config"
"time"
)
var RedisClient *redis.Client
func InitRedis() {
RedisClient = redis.NewClient(&redis.Options{
Addr: config.AppConfig.RedisAddr,
Password: config.AppConfig.RedisPassword,
DB: config.AppConfig.RedisDB,
})
}
func SetCache(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
return RedisClient.Set(ctx, key, value, expiration).Err()
}
func GetCache(ctx context.Context, key string) (string, error) {
return RedisClient.Get(ctx, key).Result()
}
در اینجا ما علاوه بر اینکه کانفیگ ردیس راه اندازی کردیم، دو متد به نام "SetCache()
" و "GetCache()
" درست کردیم که بتونیم در ردیس کلید ذخیره یا دریافت کنیم.
4. ساخت مدل
برای ساخت مدل ها یک فایل در مسیر models/user.go
ایجاد میکنیم تا مدل ها بتونیم در این پوشه ایجاد کنیم و نظم بهتری داشته باشه:
package models
type User struct {
ID uint 'json:"id" gorm:"primaryKey"'
Name string 'json:"name"'
Email string 'json:"email" gorm:"unique"'
}
در اینجا مدل User
ایجاد کردیم با 3 پراپرتی، که شما میتونید پراپرتی های دیگه هم تعریف کنید.
5. لایه ریپازیتوری (Repository)
ما یک لایه ریپازیتوری برای گرفتن دیتا از دیتابیس ایجاد میکنیم. برای ساخت ریپازیتوری از این مسیر repositories/user_repository.go
پیروی کنید:
package repositories
import (
"codenews/cache"
"codenews/config"
"codenews/models"
"context"
"fmt"
"time"
)
func GetUserByID(ctx context.Context, id uint) (*models.User, error) {
cacheKey := fmt.Sprintf("user:%d", id)
// Try to get user from cache
cachedUser, err := cache.GetCache(ctx, cacheKey)
if err == nil {
fmt.Println("Cache hit")
return cachedUser, nil
}
fmt.Println("Cache miss")
// If not in cache, fetch from DB
var user models.User
if err := config.DB.First(&user, id).Error; err != nil {
return nil, err
}
// Store in cache for 10 minutes
cache.SetCache(ctx, cacheKey, user, 10*time.Minute)
return &user, nil
}
در اینجا ما یک متد ساختیم که با استفاده از ID
بیایم یک کاربر از دیتابیس دریافت کنیم، اما در کنار این کار از کش برای کش کردن دیتا کاربر استفاده کردیم که هر 10 دقیقه این کش منقضی میشه.
6. لایه سرویس (Service)
برای ارتباط بین کنترلر و ریپازیتوری ما یک لایه سرویس هم اضافه میکنیم. این کار اختیاریه و شما میتونید لایه سرویس حذف یا حتی برای عملیات های ذخیره استفاده کنید. برای ساخت سرویس از مسیر services/user_service.go
پیروی کنید:
package services
import (
"context"
"codenews/models"
"codenews/repositories"
)
func GetUser(ctx context.Context, id uint) (*models.User, error) {
return repositories.GetUserByID(ctx, id)
}
در اینجا ما مستقیم از ریپازیتوری دیتا دریافت کردیم.
7. کنترلر (Controller)
برای ساخت کنترلر در مسیر controllers/user_controller.go
یک کنترلر ایجاد میکنیم. کنترلر ها وظیفه گرفتن دیتا و نمایش آن به صورت JSON
و.. دارند:
package controllers
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"codenews/services"
)
func GetUser(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
user, err := services.GetUser(c, uint(id))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
return
}
c.JSON(http.StatusOK, user)
}
در اینجا ما از سرویس دیتا کاربر دریافت کردیم و با استفاده از فریم ورک Gin در قالب JSON
نمایش دادیم.
8. روتنیگ (Routing)
یک فایل در مسیر routes/routes.go
برای سیستم روت اپلیکیشن ایجاد میکنیم. با استفاده از فریم ورک جین میایم روتینگ هندل میکنیم:
package routes
import (
"github.com/gin-gonic/gin"
"codenews/controllers"
)
func RegisterRoutes(router *gin.Engine) {
router.GET("/users/:id", controllers.GetUser)
}
9. بخش اصلی اپلیکیشن (Main)
خب هر اپلیکیشن گولنگی به main نیازمند هست پس ایجادش میکنیم در روت پروژه:
package main
import (
"github.com/gin-gonic/gin"
"codenews/config"
"codenews/cache"
"codenews/routes"
)
func main() {
// Load configurations
config.LoadConfig()
// Connect to database
config.ConnectDatabase()
// Initialize Redis
cache.InitRedis()
// Set up router
router := gin.Default()
routes.RegisterRoutes(router)
// Start the server
router.Run(":8080")
}
در main ما میایم هر بخش راه اندازی میکنیم. این بخش هایی که میگیم یعنی دیتابیس، کش (ردیس)، کانفیگ و.. تا اپلیکیشن ما به درستی کار کنه.
نکته: در اینجا ما مستقیما پورت ران شدن برنامه مشخص کردیم که شما میتونید پورت هم از کانفیگ بخونید.
اولین نفر باش که نظر ثبت میکنی :) یعنی یه کامنت به ما نمیرسه 😁