Go Web Frame
A modern, feature-rich web framework for Go built on top of Gin, providing a structured approach to building enterprise-grade web applications.
π Language / θ―θ¨
English β’ δΈζ
Project Overview
Go Web Frame is an opinionated web framework that enforces clean architecture through component-based design. It provides built-in dependency injection, type-safe ORM, database integration, and production-ready features like daemon/service mode out of the box.
Features
- MVC-like Architecture: Clean separation of concerns with services, controllers, and models
- β‘ Type-safe Generic ORM: Zero-boilerplate CRUD operations with generics, no reflection overhead
- Dependency Injection: Built-in DI container for managing component lifecycle
- Database Integration: SQLite, MySQL, PostgreSQL, Redis support with extensible database abstraction layer (powered by GORM)
- Connection Pool Configuration: Configurable connection pool settings (
max_open_conns, max_idle_conns, conn_max_lifetime)
- Component System: Reusable components including caching, rate limiting, captcha, QR code generation, cron scheduled tasks, and input validation
- RESTful Support: Simplified REST controller implementation
- Daemon/Service Mode: Run applications as system services on Windows, Linux, and macOS
- Auto-Configuration: Auto-loading config from JSON, YAML, or TOML files
- Advanced Logging: Structured logging powered by Zap with rotation support
- Background Tasks: Built-in runner system for background processing
- Request Filtering: HTTP middleware/filter system for cross-cutting concerns
- Route Metadata:
.WithMeta() support for attaching custom metadata to routes (enables flexible per-route authentication, permissions, etc.)
- Unified Error Handling: Automatic conversion of service errors to standardized HTTP responses
Quick Start
Installation
go get github.com/chuccp/go-web-frame
Hello World Example
package main
import (
"context"
"time"
wf "github.com/chuccp/go-web-frame"
"github.com/chuccp/go-web-frame/log"
"github.com/chuccp/go-web-frame/web"
)
func main() {
// Create web framework instance with auto config loading
app := wf.NewWithAutoConfig()
// Register a simple route
app.Get("/", func(c *web.Request) (any, error) {
return "Hello, World!", nil
})
// Run with context for graceful shutdown
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Auto shutdown after 10 seconds (example)
go func() {
time.Sleep(time.Second * 10)
cancel()
}()
if err := app.Run(ctx); err != nil {
log.PrintPanic(err)
}
}
π REST Controller Example
package main
import (
"context"
wf "github.com/chuccp/go-web-frame"
"github.com/chuccp/go-web-frame/core"
"github.com/chuccp/go-web-frame/log"
"github.com/chuccp/go-web-frame/web"
)
type UserController struct {
// Embed core.IService interface
core.IService
}
// Init controller and register routes
func (u *UserController) Init(ctx *core.Context) error {
// Register routes through context
ctx.Get("/users", u.GetUsers)
ctx.Get("/users/:id", u.GetUser)
ctx.Post("/users", u.CreateUser)
return nil
}
// Handler: get all users
func (u *UserController) GetUsers(c *web.Request) (any, error) {
// Access query parameters
page := c.Query("page")
limit := c.Query("limit")
return map[string]any{
"users": []string{"alice", "bob"},
"page": page,
"limit": limit,
}, nil
}
// Handler: get a single user by ID
func (u *UserController) GetUser(c *web.Request) (any, error) {
id := c.Param("id")
return map[string]any{
"id": id,
"name": "alice",
}, nil
}
// Handler: create a new user
func (u *UserController) CreateUser(c *web.Request) (any, error) {
var user struct {
Name string `json:"name"`
}
if err := c.BindJSON(&user); err != nil {
return nil, err
}
return map[string]any{
"id": 1,
"name": user.Name,
}, nil
}
func main() {
app := wf.NewWithAutoConfig()
app.AddRest(&UserController{})
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err := app.Run(ctx); err != nil {
log.PrintPanic(err)
}
}
The .WithMeta() feature allows you to attach arbitrary metadata to individual routes, which can then be accessed by filters for flexible cross-cutting concerns like authentication, permission checks, feature flags, caching configuration, and more.
Basic Usage:
// Create meta options
func RequireAuth() web.MetaOption {
return web.WithValue("require_auth", true)
}
func RequirePermission(perm string) web.MetaOption {
return web.WithValue("require_permission", perm)
}
// In route registration
func (c *ApiController) Init(ctx *core.Context) error {
// Public route - no auth needed
ctx.Get("/api/login", loginHandler).WithMeta(SkipAuth())
// Protected route - requires authentication
ctx.Get("/api/profile", profileHandler, RequireAuth())
// Protected route with multiple metadata options
ctx.Post("/api/admin/users", createUserHandler, RequireAuth(), RequirePermission("admin:create_user"))
return nil
}
Access metadata in a filter:
func (f *AuthFilter) Handle(fc web.FilterChain, req *web.Request) (any, error) {
meta := req.HandlerMeta()
// Check if this route requires authentication
requireAuth, ok := meta.Get("require_auth").(bool)
if ok && requireAuth {
// Skip auth if marked as public
if meta.Has("skip_auth") {
return fc.Next()
}
// Get token and verify...
token := req.Request().Header.Get("Authorization")
if token == "" {
return nil, errors.New("missing authorization token")
}
}
return fc.Next()
}
See the complete example at example/withmeta/withmeta.go
β‘ Generic ORM Example
package main
import (
"context"
wf "github.com/chuccp/go-web-frame"
"github.com/chuccp/go-web-frame/core"
"github.com/chuccp/go-web-frame/model"
)
// Define your entity struct
type User struct {
Id uint `gorm:"primaryKey"`
Name string
Age int
}
// UserModel extends generic Model
type UserModel struct {
*model.Model[*User]
}
func (u *UserModel) Init(db *core.DB, ctx *core.Context) error {
u.Model = model.NewModel[*User](db, "t_user")
// Auto create table if not exists
return u.CreateTable()
}
func main() {
app := wf.NewWithAutoConfig()
// Register model to DI container
app.AddModel(&UserModel{})
// Example ORM operations
app.Get("/users", func(c *web.Request) (any, error) {
userModel := wf.GetModel[*UserModel](c.Context())
// Query with chain API
users, err := userModel.Query().
Where("age > ?", 18).
Order("id desc").
All()
return users, err
})
app.Post("/users", func(c *web.Request) (any, error) {
userModel := wf.GetModel[*UserModel](c.Context())
// Create user
user := &User{Name: "John", Age: 25}
err := userModel.Save(user)
return user.Id, err
})
app.Put("/users/:id", func(c *web.Request) (any, error) {
userModel := wf.GetModel[*UserModel](c.Context())
id := c.ParamInt("id")
// Update user
return nil, userModel.Update().
Where("id = ?", id).
UpdateColumn("name", "John Updated")
})
app.Delete("/users/:id", func(c *web.Request) (any, error) {
userModel := wf.GetModel[*UserModel](c.Context())
id := c.ParamInt("id")
// Delete user
return nil, userModel.Delete().
Where("id = ?", id).
Delete()
})
ctx := context.Background()
app.Run(ctx)
}
Architecture Overview
Core Layers
-
Core Abstraction Layer (./core): Defines fundamental interfaces and DI container
IService: Base interface for all services requiring initialization
IModel: Data access layer interface with CRUD and table management
IRest: REST controller interface (extends IService)
IComponent: Independent components initialized with config
IRunner: Background task runners (extends IService)
IFilter: HTTP request filters/middleware (extends IService)
Context: Dependency injection container that manages all components
-
Web Layer (./web): HTTP handling built on top of Gin
- Request/response abstraction with helper methods
- Routing with support for all HTTP methods
- Filter/middleware system
- Automatic conversion of service responses to standardized HTTP responses
-
Data Access Layer (./db, ./model): Database abstraction and ORM
./db: Multi-database abstraction (MySQL, SQLite, PostgreSQL) powered by GORM
./model: Type-safe generic base model with zero-boilerplate CRUD
./sqlite: SQLite-specific configuration
./redis: Redis integration for caching and messaging
- Configurable connection pool settings for production performance tuning
-
Infrastructure Components:
./config: Configuration management with Viper (JSON/YAML/TOML)
./log: Structured logging with Zap
./component: Reusable components (cache, rate limiting, captcha, QR code, cron, validation)
./util: Comprehensive utilities (strings, time, crypto, networking, etc.)
Application Lifecycle
- Create: Initialize
WebFrame with NewWithAutoConfig() or New(config)
- Register: Add routes, controllers, models, services, components, and runners
- Configure: Customize settings, add middleware, configure logging
- Run: Start the server with
Run(ctx) or run in daemon/service mode
Configuration Example
Example YAML configuration with database connection pool:
server:
port: 8080
mode: debug # or release
web:
db:
type: mysql
host: localhost
port: 3306
username: root
password: your_password
database: your_db
charset: utf8mb4
# Connection pool settings (optional)
max_open_conns: 100
max_idle_conns: 10
conn_max_lifetime: 3600 # seconds
log:
level: info
path: ./logs/app.log
Project Structure
βββ web_frame.go # Main entry point - factory methods for WebFrame
βββ daemon.go # Daemon/service mode support for Windows/Linux/macOS
βββ core/ # Core abstractions and DI container
β βββ interface.go # Core interfaces (IService, IModel, IRest, etc.)
β βββ context.go # Dependency injection context
β βββ server.go # Server implementation managing REST groups and runners
β βββ db.go # DB wrapper
βββ web/ # Web layer built on Gin
β βββ handles.go # Route registration
β βββ request.go # Request abstraction with helper methods
β βββ response.go # Response conversion
β βββ filter.go # Filter/middleware interface
βββ db/ # Database abstraction layer
β βββ db.go # DB creation and config parsing
β βββ mysql.go # MySQL configuration and connection
β βββ sqlite.go # SQLite configuration and connection
βββ model/ # Generic ORM implementation
β βββ model.go # Base Model with CRUD operations
βββ sqlite/ # SQLite driver
βββ redis/ # Redis integration
βββ config/ # Configuration management
βββ log/ # Logging with Zap
βββ component/ # Reusable components
β βββ cache.go # Cache component
β βββ localcache.go # Local in-memory cache
β βββ rate_limit.go # Rate limiting
β βββ captcha.go # Captcha generation
β βββ qrcode.go # QR code generation
β βββ cron.go # Cron scheduled tasks
β βββ validate.go # Input validation
βββ util/ # Utility functions
βββ example/ # Example applications
βββ helloworld/ # Basic hello world example
βββ rest/ # REST controller example
βββ model/ # ORM model example
βββ filter/ # Custom HTTP filters example
βββ background/ # Background tasks/runners example
βββ withmeta/ # Route metadata .WithMeta() example
Common Development Commands
Build and Run Examples
# Run the hello world example
go run example/helloworld/helloworld.go
# Run the REST example
go run example/rest/rest.go
# Run the ORM model example
go run example/model/model.go
# Run the filters example
go run example/filter/filter.go
# Run the background tasks example
go run example/background/background.go
# Run the route metadata .WithMeta() example
go run example/withmeta/withmeta.go
# Build the framework (library only)
go build
Testing
# Run all tests
go test ./...
# Run tests in a specific package
go test ./core
go test ./web
# Run tests with verbose output
go test -v ./core
# Run a specific test case
go test -v ./core -run TestSpecificFunction
# Format all code with gofmt
gofmt -w ./...
# Alternative formatting with gofumpt (if installed)
gofumpt -w ./...
# Install linter
go install golang.org/x/lint/golint@latest
# Run linter
golint ./...
Dependency Management
# Add a new dependency
go get github.com/example/package
# Update dependencies
go get -u ./...
# Tidy up go.mod and go.sum
go mod tidy
Daemon Mode
# Run application as a system daemon/service
# (Requires implementing AppService interface)
go run your_app.go
# Stop a running daemon
go run your_app.go -stop
Development Notes
- The framework follows Go conventions and uses standard Go tooling
- All components implement the
IService interface with Init(ctx) method
- Dependency injection is done through the context - use
wf.GetService[T](ctx) to retrieve services
- Connection pool has reasonable defaults that work for most applications
- SQLite is recommended for development and small applications, MySQL for production
Documentation
Contributing
Contributions are welcome! Please feel free to submit Issues and Pull Requests. Before submitting a PR:
- Run tests to ensure everything passes
- Keep the code style consistent with the project
- Add appropriate tests for new features
- Update related documentation
License
MIT License - see LICENSE for details