wf

package module
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

README ΒΆ

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)
    }
}
🏷️ Route Metadata with .WithMeta()

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
  1. 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
  2. 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
  3. 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
  4. 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
  1. Create: Initialize WebFrame with NewWithAutoConfig() or New(config)
  2. Register: Add routes, controllers, models, services, components, and runners
  3. Configure: Customize settings, add middleware, configure logging
  4. 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
Formatting and Linting
# 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:

  1. Run tests to ensure everything passes
  2. Keep the code style consistent with the project
  3. Add appropriate tests for new features
  4. Update related documentation

License

MIT License - see LICENSE for details

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

This section is empty.

Functions ΒΆ

func GetComponent ΒΆ

func GetComponent[T core.IComponent](c *core.Context) T

func GetFilter ΒΆ added in v0.1.3

func GetFilter[T core.IFilter](c *core.Context) T

func GetModel ΒΆ

func GetModel[T core.IModel](c *core.Context) T

func GetReNewModel ΒΆ

func GetReNewModel[T core.IModel](db *db2.DB, c *core.Context) T

func GetRunner ΒΆ

func GetRunner[T core.IRunner](c *core.Context) T

func GetService ΒΆ

func GetService[T core.IService](c *core.Context) T

func LoadAutoConfig ΒΆ

func LoadAutoConfig() *config2.Config

func LoadConfig ΒΆ

func LoadConfig(paths ...string) (*config2.Config, error)

func RunDaemon ΒΆ

func RunDaemon(appService AppService, svcConfig *service.Config)

func UnmarshalKeyConfig ΒΆ added in v0.1.3

func UnmarshalKeyConfig[T any](key string, c *core.Context) (T, error)

Types ΒΆ

type AppDaemon ΒΆ

type AppDaemon struct {
	// contains filtered or unexported fields
}

func (*AppDaemon) Start ΒΆ

func (a *AppDaemon) Start(s service.Service) error

func (*AppDaemon) Stop ΒΆ

func (a *AppDaemon) Stop(s service.Service) error

type AppService ΒΆ

type AppService interface {
	Start() error
	Close() error
}

type DefaultConverter ΒΆ added in v0.1.3

type DefaultConverter struct {
	// contains filtered or unexported fields
}

func (*DefaultConverter) Init ΒΆ added in v0.1.3

func (receiver *DefaultConverter) Init(ctx *core.Context) error

func (*DefaultConverter) Request ΒΆ added in v0.1.3

func (receiver *DefaultConverter) Request(filterChain web.FilterChain, request *web.Request)

type DefaultRest ΒΆ added in v0.1.3

type DefaultRest struct {
	// contains filtered or unexported fields
}

func (*DefaultRest) Init ΒΆ added in v0.1.3

func (receiver *DefaultRest) Init(ctx *core.Context) error

type WebFrame ΒΆ

type WebFrame struct {
	// contains filtered or unexported fields
}

func New ΒΆ

func New(config config2.IConfig) *WebFrame

func NewWithAutoConfig ΒΆ added in v0.1.3

func NewWithAutoConfig() *WebFrame

func (*WebFrame) AddComponent ΒΆ

func (w *WebFrame) AddComponent(component ...core.IComponent)

func (*WebFrame) AddFilter ΒΆ added in v0.1.3

func (w *WebFrame) AddFilter(filters ...core.IFilter)

func (*WebFrame) AddModel ΒΆ

func (w *WebFrame) AddModel(model ...core.IModel)

func (*WebFrame) AddRest ΒΆ

func (w *WebFrame) AddRest(rest ...core.IRest)

func (*WebFrame) AddRunner ΒΆ

func (w *WebFrame) AddRunner(runner ...core.IRunner)

func (*WebFrame) AddService ΒΆ

func (w *WebFrame) AddService(service ...core.IService)

func (*WebFrame) Any ΒΆ added in v0.1.3

func (w *WebFrame) Any(relativePath string, handlers ...web.HandlerFunc) *web.HandlerInfo

func (*WebFrame) Delete ΒΆ added in v0.1.3

func (w *WebFrame) Delete(relativePath string, handlers ...web.HandlerFunc) *web.HandlerInfo

func (*WebFrame) Get ΒΆ added in v0.1.3

func (w *WebFrame) Get(relativePath string, handlers ...web.HandlerFunc) *web.HandlerInfo

func (*WebFrame) GetDefaultModelGroup ΒΆ added in v0.1.4

func (w *WebFrame) GetDefaultModelGroup() core.IModelGroup

func (*WebFrame) NewEmptyModelGroup ΒΆ added in v0.1.4

func (w *WebFrame) NewEmptyModelGroup(name string) *core.ModelGroup

func (*WebFrame) NewModelGroup ΒΆ added in v0.1.4

func (w *WebFrame) NewModelGroup(db *db2.DB, name string) *core.ModelGroup

func (*WebFrame) NewRestGroup ΒΆ added in v0.1.3

func (w *WebFrame) NewRestGroup(serverConfig *web.ServerConfig) *core.RestGroup

func (*WebFrame) Post ΒΆ added in v0.1.3

func (w *WebFrame) Post(relativePath string, handlers ...web.HandlerFunc) *web.HandlerInfo

func (*WebFrame) Put ΒΆ added in v0.1.3

func (w *WebFrame) Put(relativePath string, handlers ...web.HandlerFunc) *web.HandlerInfo

func (*WebFrame) Run ΒΆ added in v0.1.3

func (w *WebFrame) Run(ctx context.Context) error

func (*WebFrame) SetDefaultDB ΒΆ added in v0.1.4

func (w *WebFrame) SetDefaultDB(db *db2.DB)

func (*WebFrame) Start ΒΆ

func (w *WebFrame) Start() error

func (*WebFrame) Test ΒΆ added in v0.5.1

func (w *WebFrame) Test(f func(ctx *core.Context) error) error

Directories ΒΆ

Path Synopsis
component
example
background command
config command
filter command
helloworld command
rest command
withmeta command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL