Ginx Framework Development Guide
This skill provides comprehensive guidance for developing services with the Ginx framework, a Go web framework built on top of Gin that provides enterprise-level features and integrations.
Quick Start
-
Creating a new project? Use the initialization script:
./scripts/init_project.sh my-project-nameThis will use
gotoolto create a standard Ginx project structure. The script automatically detects your platform and downloads gotool if needed. -
New to Ginx? Start with architecture.md to understand the framework structure and initialization flow
-
Building HTTP APIs? See http-development.md for routes, controllers, middleware, and request/response patterns
-
Working with databases? Check data-layer.md for MySQL (GORM) and Redis operations
-
Managing configuration? Read configuration.md for YAML config and environment variable handling
-
Deploying applications? Refer to deployment.md for Docker, Kubernetes, and process management
-
Need common patterns? See patterns.md for service layer, error handling, logging, and testing patterns
Core Responsibilities
Project Structure & Initialization
Ginx uses a plugin-based initialization pattern where modules register themselves during package init:
// main.go - Application entry
import (
_ "myproject/app/http"
_ "myproject/app/grpc"
_ "myproject/app/task"
)
func main() {
server.Run(app.Config.Base)
}
Standard structure:
project/
├── main.go # Entry point
├── app/
│ ├── app.go # Global initialization, helpers
│ ├── config/ # Configuration structs
│ ├── http/ # HTTP server, routes, controllers, middleware
│ ├── grpc/ # gRPC server
│ ├── task/ # Background tasks
│ ├── models/ # Database models
│ ├── svc/ # Service layer (business logic)
│ └── utils/ # Utilities
├── config/ # YAML config files
└── Dockerfile
HTTP Development
Route Registration - Organize routes by domain in app/http/routes/:
func Reg(router *gin.Engine) {
router.GET("/", home.Index)
auth := router.Group("/auth")
auth.POST("/login", auth.Login)
protected := router.Group("/api", auth middleware)
protected.GET("/users", user.List)
}
Controllers - Thin handlers that delegate to service layer:
func Create(ctx *gin.Context) {
var req CreateUserReq
if err := ctx.ShouldBindJSON(&req); err != nil {
rsp.JSONErr(ctx, &rsp.Values{Code: rsp.CodeParamErr, Msg: err.Error()})
return
}
user, err := userService.CreateUser(ctx, &req)
rsp.JSONOk(ctx, user)
}
Middleware - Use at global, group, or route level:
// Global
router.Use(logger.Logger(), tracer.Tracer())
// Group
api := router.Group("/api", auth.Required)
// Route
router.GET("/admin", auth.AdminOnly, admin.Dashboard)
Database Operations
MySQL with GORM - Use read/write split:
// Write operations
app.DbW(ctx).Create(&user)
app.DbW(ctx).Updates(updates)
// Read operations
app.DbR(ctx).First(&user, id)
app.DbR(ctx).Find(&users)
// Named instances
app.DbW(ctx, "abc")
Redis - String, hash, list, set, sorted set operations:
// String
app.RedisW().Set(ctx, key, value, ttl)
val, _ := app.RedisR().Get(ctx, key).Result()
// Hash
app.RedisW().HSet(ctx, key, field, value)
val, _ := app.RedisR().HGet(ctx, key, field).Result()
Always pass gin.Context for tracing: app.DbW(ctx), app.RedisR().Get(ctx, ...)
Configuration
YAML-based config with environment files (config.yaml, config-production.yaml) and environment variable overrides:
mysql_db:
default:
write:
host: 127.0.0.1
port: 3306
read:
host: slave.example.com
# Override with env vars
# GINX_MYSQL_DB_DEFAULT_WRITE_HOST=prod.db.example.com
Service Layer Pattern
Separate business logic from controllers:
app/http/controllers/ → Thin handlers (bind request, call service, format response)
app/svc/user/ → Business logic, reusable across HTTP/gRPC/tasks
// Service
func (s *Service) CreateUser(ctx context.Context, dto *CreateUserDTO) (*UserDTO, error) {
// Business logic
if err := app.DbW(ctx).Create(user).Error; err != nil {
return nil, err
}
return &UserDTO{...}, nil
}
// Controller
func Create(ctx *gin.Context) {
result, err := userService.CreateUser(ctx, &req)
rsp.JSONOk(ctx, result)
}
Deployment
Docker - Multi-stage build for minimal image:
FROM golang:1.21-alpine AS builder
RUN go build -o /app/myapp .
FROM alpine:latest
COPY --from=builder /app/myapp .
CMD ["./myapp"]
Process Management - PM2 (pmon2), systemd, or supervisor:
pmon2 start app.yaml
sudo systemctl start myapp
Graceful Restart - Use SIGUSR2 on physical machines, rely on K8s in containers.
Reference Materials
Detailed documentation in references/:
- architecture.md - Framework architecture, server registration model, initialization flow, request lifecycle
- http-development.md - Route registration, controllers, middleware, request binding, response formatting, authentication
- data-layer.md - MySQL/GORM operations, Redis operations, database best practices, caching strategies
- configuration.md - YAML configuration, environment variables, custom config sections, runtime configuration
- patterns.md - Service layer pattern, error handling, logging, testing, common utilities (pagination, retry, validation)
- deployment.md - Docker containerization, Docker Compose, process management, graceful restart, monitoring, health checks
Scripts
Utility script in scripts/:
- init_project.sh - Project initialization script using gotool. Automatically detects your platform, downloads gotool if needed, and creates a new Ginx project with the standard structure. If gotool fails, provides fallback to the web-based generator at http://beta.sothos.qihoo.net/app/toolkit/gotool
Usage:
./scripts/init_project.sh my-project-name
Critical Patterns
Always Pass Context
// Good - enables tracing
app.DbW(ctx).Create(&user)
app.RedisR().Get(ctx, key).Result()
// Bad - breaks tracing
app.DbW().Create(&user)
Use Read/Write Split
app.DbR(ctx).Find(&users) // Read queries
app.DbW(ctx).Create(&user) // Writes
Preserve Request Body in Middleware
// Read body
body, _ := ctx.GetRawData()
// ... process
// Restore for controller
ctx.Set(gin.BodyBytesKey, body)
ctx.Next()
Unified Response Format
rsp.JSONOk(ctx, data)
rsp.JSONErr(ctx, &rsp.Values{Code: rsp.CodeParamErr, Msg: "Invalid"})
Common Tasks
Create new route: Add to appropriate file in app/http/routes/, register in routes.Reg()
Add middleware: Implement in app/http/middleware/, apply at global/group/route level
Add service: Create in app/svc/domain/service.go, call from controller
Configure database: Edit config/config.yaml with mysql_db section
Enable metrics: Set metrics.enable: true in config, access at /metrics
Add tracing: Set trace.enable: true, pass gin.Context to DB/Redis calls
Deploy: Build with CGO_ENABLED=0 GOOS=linux go build, use Docker or systemd

