Go: المشروع المتكامل: واجهة برمجة تطبيقات التجارة…
آخر تحديث: 2026-08-26
لدينا البنية التحتية، ولدينا نظام الأمان — والآن، دعونا نبدأ التشغيل.
من السطر الأول من الكود وحتى الجاهزية للإنتاج: وثائق Swagger، والإغلاق التدريجي، والنشر عبر Docker، وضبط pprof، والمراقبة بواسطة Prometheus. أصبحت واجهة برمجة تطبيقات التجارة الإلكترونية الخاصة بـ«بوب» جاهزة لاستقبال المستخدمين الحقيقيين.
1. ستتعلم
- الإنشاء التلقائي للوثائق لـ Swagger / OpenAPI
server.Shutdownالإغلاق السلس- عملية بناء Docker متعددة المراحل + Docker Compose للمكدس الكامل
- تكامل نقطة نهاية تحليل الأداء pprof
- تعرض مؤشرات بروميثيوس
- تصميم معايير تقييم الفحص الصحي
2. القصة: الليلة التي سبقت الإطلاق
(1) نقاط الضعف: عدم وجود توثيق، وعدم وجود مراقبة، والنشر اليدوي
واجهة برمجة تطبيقات التجارة الإلكترونية الخاصة بـ«بوب» تعمل بكامل طاقتها، لكن فريق العمليات رفض قبولها:
«قال فريق العمليات: "بدون وثائق واجهة برمجة التطبيقات (API)، لا يمكن للواجهة الأمامية التكامل معها. وبدون فحوصات الحالة، لا يمكننا معرفة ما إذا كانت الخدمة تعمل أم لا. وبدون المراقبة، لن نعرف حتى ما إذا كانت الخدمة قد تعطلت. وما زلنا مضطرين إلى نقل الملفات الثنائية يدويًّا عبر SCP من أجل النشر — وهذا أمر بدائي للغاية."»
قائمة التحقق قبل الإطلاق:
❌ API docs → Frontend has to ask "what fields does this endpoint return?" every time
❌ Graceful shutdown → Kill process causes in-flight orders to be lost
❌ Docker deploy → SCP binary to server, start manually
❌ Performance monitoring → Don't know which part of the API is slow
(2) هدف الدرس: جاهز للإنتاج
✅ Swagger docs → Frontend self-service browsing
✅ Graceful Shutdown → Signal handling + wait for connections to close
✅ Docker Compose → One command to start the full stack
✅ pprof + Prometheus → Performance visualization
3. التنفيذ الكامل
▶ مثال: الإغلاق السلس
⚙️ المتطلبات الأساسية: قم بتشغيل
go get github.com/mattn/go-sqlite3(يتطلب CGO؛ أو استخدمmodernc.org/sqliteكبديل للحصول على برنامج تشغيل مخصص للعبة «غو» فقط)
// cmd/server/main.go
package main
import (
"context"
"database/sql"
"encoding/json"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"ecommerce/internal/handler"
"ecommerce/internal/repository"
"ecommerce/internal/service"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./ecommerce.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(5 * time.Minute)
// Dependency injection
userRepo := repository.NewUserRepository(db)
productRepo := repository.NewProductRepository(db)
orderRepo := repository.NewOrderRepository(db)
userSvc := service.NewUserService(userRepo)
productSvc := service.NewProductService(productRepo)
orderSvc := service.NewOrderService(orderRepo, productRepo, userRepo)
userHandler := handler.NewUserHandler(userSvc)
productHandler := handler.NewProductHandler(productSvc)
orderHandler := handler.NewOrderHandler(orderSvc)
mux := http.NewServeMux()
userHandler.Register(mux)
productHandler.Register(mux)
orderHandler.Register(mux)
// Health check endpoint
mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
mux.HandleFunc("GET /ready", func(w http.ResponseWriter, r *http.Request) {
if err := db.Ping(); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(map[string]string{"status": "not ready"})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "ready"})
})
server := &http.Server{
Addr: ":8080",
Handler: mux,
// Timeout settings (prevent slowloris attacks)
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
ReadHeaderTimeout: 5 * time.Second,
}
// Graceful Shutdown
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
sig := <-sigCh
log.Printf("Received signal %v, shutting down...", sig)
// Give in-flight requests up to 30 seconds to complete
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Printf("Forced shutdown: %v", err)
}
}()
log.Println("E-commerce API listening on :8080")
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
log.Println("Server shut down safely")
}
▶ مثال: التكامل بين pprof وPrometheus
⚙️ المتطلبات المسبقة: تشغيل
go get github.com/prometheus/client_golang/prometheusوgo get github.com/prometheus/client_golang/prometheus/promhttp
// monitoring.go
package main
import (
"net/http"
"net/http/pprof"
"runtime"
"strconv"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Prometheus metrics
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total HTTP requests",
},
[]string{"method", "path", "status"},
)
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: []float64{.001, .005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5},
},
[]string{"method", "path"},
)
activeGoroutines = prometheus.NewGaugeFunc(
prometheus.GaugeOpts{
Name: "go_goroutines_active",
Help: "Current number of goroutines",
},
func() float64 {
return float64(runtime.NumGoroutine())
},
)
)
func init() {
prometheus.MustRegister(httpRequestsTotal)
prometheus.MustRegister(httpRequestDuration)
prometheus.MustRegister(activeGoroutines)
}
// Prometheus middleware
func prometheusMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// Wrap ResponseWriter to get status code
wrapped := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
next.ServeHTTP(wrapped, r)
duration := time.Since(start)
httpRequestsTotal.WithLabelValues(
r.Method, r.URL.Path, strconv.Itoa(wrapped.statusCode),
).Inc()
httpRequestDuration.WithLabelValues(
r.Method, r.URL.Path,
).Observe(duration.Seconds())
})
}
type responseWriter struct {
http.ResponseWriter
statusCode int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
// Register pprof and Prometheus endpoints in main
func registerMonitoring(mux *http.ServeMux) {
// pprof endpoints
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
// Prometheus metrics
mux.Handle("/metrics", promhttp.Handler())
}
func main() {
mux := http.NewServeMux()
registerMonitoring(mux)
// Example business endpoint
mux.HandleFunc("GET /api/products", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"products":[]}`))
})
// Health check
mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok"}`))
})
log.Println("Monitoring + API server listening on :8080")
http.ListenAndServe(":8080", prometheusMiddleware(mux))
}
▶ مثال: نشر Docker
# Dockerfile (Multi-stage Build)
FROM golang:1.22-alpine AS builder
WORKDIR /app
# Dependency cache
COPY go.mod go.sum ./
RUN go mod download
# Source + compile
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server ./cmd/server
# === Run stage ===
FROM alpine:3.19
RUN apk --no-cache add ca-certificates tzdata
COPY --from=builder /app/server /server
EXPOSE 8080
EXPOSE 6060 # pprof
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -qO- http://localhost:8080/health || exit 1
CMD ["/server"]
# docker-compose.yml
version: '3.8'
services:
api:
build: .
ports:
- "8080:8080"
- "6060:6060" # pprof
environment:
- DB_PATH=/data/ecommerce.db
- GIN_MODE=release
volumes:
- data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
volumes:
data:
prometheus_data:
grafana_data:
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'ecommerce-api'
static_configs:
- targets: ['api:8080']
metrics_path: '/metrics'
▶ مثال: وثائق Swagger
// Generate OpenAPI docs from comments (use with swag tool)
// Package handler handles HTTP requests.
//
// E-commerce API
//
// Schemes: http
// Host: localhost:8080
// BasePath: /api/v1
// Version: 1.0.0
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// swagger:meta
package handler
import "ecommerce/pkg/model"
// User information
// swagger:model
type User struct {
ID int `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
}
// RegisterUser registers a new user
// swagger:route POST /api/v1/register users registerUser
//
// Register a new user
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Responses:
// 201: User
// 400: ErrorResponse
// 409: ErrorResponse
func (h *UserHandler) RegisterUser(w http.ResponseWriter, r *http.Request) {
// handler logic
}
// swagger:parameters registerUser
type RegisterUserParams struct {
// in: body
Body model.RegisterRequest
}
// ErrorResponse error response
// swagger:response
type ErrorResponse struct {
// in: body
Body struct {
Error string `json:"error"`
}
}
# Install swag CLI
$ go install github.com/swaggo/swag/cmd/swag@latest
# Generate docs
$ swag init -g cmd/server/main.go
# Access docs
# http://localhost:8080/swagger/index.html
(5) قائمة التحقق من الإطلاق
✅ Graceful Shutdown — wait for requests to complete after kill
✅ Health Check — /health and /ready endpoints
✅ pprof — /debug/pprof/ performance analysis
✅ Prometheus — /metrics endpoint exposed
✅ Swagger — Auto-generated API documentation
✅ Docker — Multi-stage build, image < 20 MB
✅ docker-compose — One command to start the full stack
✅ ReadTimeout / WriteTimeout — prevent slowloris attacks
✅ DB connection pool — MaxOpenConns=25, MaxIdleConns=10
✅ server.Shutdown — SIGINT/SIGTERM handling
❓ أسئلة شائعة
server.Shutdown حتى تكتمل جميع طلبات HTTP النشطة (حتى انتهاء المهلة المحددة) قبل إغلاق المستمع. وإذا تم إنهاء العملية على الفور، فستتوقف الطلبات التي يجري معالجتها حاليًا — مما يؤدي إلى عدم اتساق ترتيب البيانات./debug/pprof/ باستخدام برمجيات وسيطة للتوثيق؛ (3) قم بتمكينها فقط في بيئة الاختبار. في بيئة الإنتاج، يوصى بتمكين تحليل الأداء مؤقتًا فقط عند الحاجة.promhttp.Handler() لعرض المقاييس على نقطة النهاية /metrics. يقوم خادم Prometheus باستخراج البيانات من هذه النقطة بشكل دوري. يتصل Grafana بمصدر بيانات Prometheus ويقوم بإنشاء تمثيلات مرئية. المقاييس القياسية: عدد الطلبات، وتوزيع زمن الاستجابة، ومعدل الأخطاء، وعدد goroutines، وعدد أحداث GC.swaggo/swag — اكتب تعليقات بتنسيق محدد داخل كود المعالج الخاص بك، ثم قم بتشغيل swag init لإنشاء المجلد docs/. استخدم swaggo/http-swagger لربط الوثائق بنقطة النهاية /swagger/. تنسيق التعليقات: // swagger:route، // swagger:model، // swagger:parameters.depends_on للتحكم في ترتيب بدء التشغيل، واستخدم volumes لحفظ البيانات. قم بتشغيل docker-compose up -d لبدء تشغيل جميع الخدمات بأمر واحد. في بيئة الإنتاج، استخدم Docker Stack أو Kubernetes.📖 ملخص
- الإغلاق السلس:
server.Shutdown(ctx)+signal.Notify - إعدادات مهلة الانتظار: مهلة القراءة / مهلة الكتابة / مهلة الخمول
- pprof: نقطة النهاية
/debug/pprof/(غير متاحة خارجيًا) - Prometheus: نقطة النهاية
/metrics+ المقاييس المخصصة - Swagger:
swaggo/swagيُنشئ OpenAPI من التعليقات - دوكر: عملية بناء متعددة المراحل + فحص الحالة (HEALTHCHECK)
- Docker Compose: واجهة برمجة التطبيقات (API) + Prometheus + Grafana
- الفحوصات الصحية:
/health(يعمل) +/ready(جاهز)
📝 تمارين
-
أساسي (مستوى الصعوبة ⭐): أضف إعدادات الإغلاق التدريجي ووقت الانتظار إلى واجهة برمجة تطبيقات التجارة الإلكترونية التي تم تناولها في هذا الدرس. استخدم
curlلاختبار نقاط النهاية/healthو/ready. استخدمkill -SIGTERM <pid>لاختبار الإغلاق التدريجي. -
متقدم (صعوبة ⭐⭐): تنفيذ نشر كامل قائم على Docker. المتطلبات: (1) ملف Dockerfile مع بناء متعدد المراحل؛ (2) ملف docker-compose.yml (API + Prometheus + Grafana)؛ (3) HEALTHCHECK؛ (4) نقطة نهاية pprof (منفذ داخلي فقط)؛ (5) التحقق من أن جميع الخدمات تبدأ بشكل طبيعي بعد تشغيل
docker-compose up. -
التحدي (الصعوبة ⭐⭐⭐): تنفيذ مراقبة Prometheus + لوحات معلومات Grafana. المتطلبات: (1) إضافة برمجيات الوسيطة Prometheus إلى واجهة برمجة التطبيقات (عدد الطلبات، زمن الاستجابة، معدل الأخطاء)؛ (2) إضافة المقاييس التشغيلية (مثل عدد الطلبات التي تم إنشاؤها، وعدد المستخدمين المسجلين)؛ (3) تضمين Prometheus و Grafana في ملف Docker Compose؛ (4) استيراد أو إنشاء لوحة معلومات Grafana لعرض QPS، وزمن الاستجابة P99، ومعدل الأخطاء، وعدد goroutines؛ (5) التحقق من صحة المقاييس باستخدام Grafana بعد إجراء اختبار الحمل.
🎉 تهانينا! لقد أكملت جميع الدروس الثلاثين في دورة Go التعليمية! بدءًا من "Hello World" وصولاً إلى واجهة برمجة تطبيقات (API) للتجارة الإلكترونية جاهزة للاستخدام في بيئة الإنتاج، فقد أتقنت مجموعة المهارات الكاملة اللازمة لتطوير الخلفية باستخدام لغة Go.