wf

package module
v1.0.14 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

Go Web Frame

Build a CRUD backend in Go with zero ORM boilerplate. Define a struct, embed a generic Model — typed queries, pagination, and context propagation come with it.


🌐 Language English中文繁體中文日本語


Overview

Go Web Frame is an integrated backend toolkit. Routing, ORM, and caching are pre-integrated — no need to pick and wire them separately.

The core is a generic Model layer that eliminates CRUD boilerplate. Define an entity struct, embed Model[T], and the compiler checks types from database to handler. No interface{}, no code generation.

// Define once, use everywhere
type User struct {
    Id   uint   `gorm:"primaryKey;autoIncrement"`
    Name string
}

type UserModel struct {
    *model.EntryModel[*User, uint]   // ← all CRUD comes from this
}

func (m *UserModel) Init(db *db.DB, c *core.Context) error {
    m.EntryModel = model.NewEntryModel[*User, uint](db, "t_user")
    return m.CreateTable()
}

// That's your model. Now use it anywhere:
user, _ := userModel.FindByPK(1)          // → *User
users, _ := userModel.FindAll()            // → []*User
users, _ := userModel.Query().Where("age > ?", 18).Order("id desc").All()
total, _ := userModel.Query().Where("status = ?", 1).Count()
users, total, _ := userModel.Page(&web.Page{PageNo: 1, PageSize: 10})
userModel.Update().Where("id = ?", 1).UpdateColumn("name", "new name")
userModel.DeleteByPK(1)

Also included: routing (Gin), auth filters, WebSocket, SSE, CORS, rate limiting, cron, validation, caching, HTTPS (Let's Encrypt auto-cert or local certificates), multi-DB (MySQL / PostgreSQL / SQLite / Redis) — all wired up and configured from one YAML file.


Quick Start

30 seconds: Hello World
go get github.com/chuccp/go-web-frame
package main

import (
    "context"
    wf "github.com/chuccp/go-web-frame"
    "github.com/chuccp/go-web-frame/config"
    "github.com/chuccp/go-web-frame/web"
)

func main() {
    builder := wf.NewBuilder(config.LoadAutoConfig())
    builder.Get("/", func(c *web.Request) (any, error) {
        return "Hello, World!", nil
    })
    builder.Build().Run(context.Background())
}
go run main.go
# → http://localhost:19009
5 minutes: REST + Database

Create application.yml:

web:
  db:
    type: sqlite
    path: ./data.db

Create main.go:

package main

import (
    "context"
    wf "github.com/chuccp/go-web-frame"
    "github.com/chuccp/go-web-frame/config"
    "github.com/chuccp/go-web-frame/core"
    "github.com/chuccp/go-web-frame/db"
    "github.com/chuccp/go-web-frame/model"
    "github.com/chuccp/go-web-frame/web"
)

// ── Entity ──
type User struct {
    Id   uint   `gorm:"primaryKey;autoIncrement"`
    Name string `gorm:"size:255"`
}

// ── Model (zero CRUD boilerplate) ──
type UserModel struct {
    *model.EntryModel[*User, uint]
}

func (m *UserModel) Init(database *db.DB, ctx *core.Context) error {
    m.EntryModel = model.NewEntryModel[*User, uint](database, "t_user")
    return m.CreateTable()
}

// ── Controller ──
type UserController struct {
    core.IService
    userModel *UserModel
}

func (c *UserController) Init(ctx *core.Context) error {
    c.userModel = wf.GetModel[*UserModel](ctx)

    ctx.Get("/users", c.List)
    ctx.Get("/users/:id", c.Get)
    ctx.Post("/users", c.Create)
    ctx.Put("/users/:id", c.Update)
    ctx.Delete("/users/:id", c.Delete)
    return nil
}

func (c *UserController) List(req *web.Request) (any, error) {
    return c.userModel.FindAll()
}

func (c *UserController) Get(req *web.Request) (any, error) {
    return c.userModel.FindByPK(req.ParamUint("id"))
}

func (c *UserController) Create(req *web.Request) (any, error) {
    var user User
    if err := req.BindJSON(&user); err != nil {
        return nil, err
    }
    return &user, c.userModel.Save(&user)
}

func (c *UserController) Update(req *web.Request) (any, error) {
    var user User
    if err := req.BindJSON(&user); err != nil {
        return nil, err
    }
    user.Id = req.ParamUint("id")
    return nil, c.userModel.UpdateByPK(&user)
}

func (c *UserController) Delete(req *web.Request) (any, error) {
    return nil, c.userModel.DeleteByPK(req.ParamUint("id"))
}

// ── Main ──
func main() {
    builder := wf.NewBuilder(config.LoadAutoConfig())
    builder.Model(&UserModel{})
    builder.Rest(&UserController{})
    builder.Build().Run(context.Background())
}
curl http://localhost:19009/users              # → [{"Id":1,"Name":"alice"}]
curl http://localhost:19009/users/1            # → {"Id":1,"Name":"alice"}
curl -X POST ... -d '{"Name":"bob"}'          # → {"Id":2,"Name":"bob"}

The table is auto-created. All CRUD works. No SQL written, no ORM wiring code needed.


Working with Data

Model Tier
Type What you get Use when
Model[T] Save, Query(), Update(), Delete(), CreateTable(), WithContext() Full control with fluent builders
EntryModel[T, PK] Everything in Model + FindByPK, FindAll, DeleteByPK, UpdateByPK, UpdateColumn, Page Entity has a primary key (most common)

PK can be uint, int, string, or any type satisfying ~uint | ~int | ~string.

Common Queries
m := userModel.WithContext(req.Ctx())   // context auto-propagates to all DB calls

// Fetch
user, err := m.FindByPK(1)                          // by primary key
users, err := m.FindAll()                            // all records
user, err := m.Query().Where("email = ?", email).One()
users, err := m.Query().Where("status = ?", 1).Order("id desc").List(100)

// Pagination
page := &web.Page{PageNo: 1, PageSize: 10}
users, total, err := m.Query().Where("age > ?", 18).Page(page)
pageAble, err := m.Query().Where("age > ?", 18).PageForWeb(page)  // returns PageAble[*User]

// Counting
count, err := m.Query().Where("status = ?", 1).Count()

// Associations (GORM Preload)
users, err := m.Query().Preload("Orders").Preload("Profile").All()
user, err := m.Query().Where("id = ?", 1).Preload("Orders").One()

// Joins
users, err := m.Query().Joins("JOIN orders ON orders.user_id = t_user.id").All()
Common Writes
// Insert
err := m.Save(&User{Name: "alice"})

// Update by primary key
user.Name = "new name"
err := m.UpdateByPK(user)

// Update single column
err := m.UpdateColumn(1, "status", 0)

// Conditional update
err := m.Update().Where("status = ?", 0).UpdateForMap(map[string]any{"status": 1})

// Delete
err := m.DeleteByPK(1)
err := m.Delete().Where("status = ?", -1).Delete()
Compared to Raw GORM
// Go Web Frame
m := userModel.WithContext(req.Ctx())
user, _ := m.FindByPK(1)
users, total, _ := m.Query().Where("age > ?", 18).Page(&web.Page{PageNo: 1, PageSize: 10})

// Raw GORM — use GetGorm() to access *gorm.DB directly
var user User
db.GetGorm().WithContext(ctx).Table("t_user").Where("id = ?", 1).First(&user)
var users []User
db.GetGorm().WithContext(ctx).Table("t_user").Where("age > ?", 18).Offset(0).Limit(10).Find(&users)
var total int64
db.GetGorm().WithContext(ctx).Table("t_user").Where("age > ?", 18).Count(&total)

EntryModel is a convenience wrapper — it reduces boilerplate, not restricts you. When built-in methods aren't enough (complex JOINs, subqueries, window functions), call db.GetGorm() and use the full GORM ecosystem directly. Mix both styles freely.

Every call in raw GORM repeats the table name, the context, and the type. Go Web Frame binds those once at construction. The difference adds up fast when you have 20+ models.


Organizing a Real Project

The Builder: One Place to Register Everything
builder := wf.NewBuilder(config.LoadAutoConfig())

// Infrastructure (runs first)
builder.Filter(&cors.Filter{})        // CORS headers
builder.Filter(&AuthFilter{})         // auth check

// Data layer
builder.Model(&UserModel{})
builder.Model(&OrderModel{})
builder.Model(&ProductModel{})

// Business logic
builder.Service(&UserService{})       // shared business logic
builder.Service(&PaymentService{})

// HTTP layer
builder.Rest(&UserController{})
builder.Rest(&OrderController{})

// Background work
builder.Runner(&CleanupTask{})

// Done
app := builder.Build()
app.Run(ctx)

Registration order matters: filters initialize first, then models, then services, then controllers, then runners. Dependencies resolve automatically through Init().

Getting Dependencies at Runtime
// In any Init() or handler, get what you need by type:
userModel := wf.GetModel[*UserModel](ctx)
userService := wf.GetService[*UserService](ctx)
authFilter := wf.GetFilter[*AuthFilter](ctx)
cleanupTask := wf.GetRunner[*CleanupTask](ctx)

No string keys, no type assertions. The generic function handles it.

Service Layer: Shared Business Logic

When multiple controllers need the same logic, extract a service:

type UserService struct {
    core.IService
    userModel *UserModel
}

func (s *UserService) Init(ctx *core.Context) error {
    s.userModel = wf.GetModel[*UserModel](ctx)
    return nil
}

func (s *UserService) GetActiveUsers() ([]*User, error) {
    return s.userModel.Query().Where("status = ?", 1).All()
}

// Register:
builder.Service(&UserService{})

// Use in controller:
userService := wf.GetService[*UserService](ctx)
users, _ := userService.GetActiveUsers()
Model Groups: Multiple Databases
// Default database
builder.Model(&UserModel{}, &LogModel{})

// Separate database for analytics
analyticsGroup := wf.NewModelGroupBuilder().
    Name("analytics").
    DB(analyticsDB).
    Model(&ReportModel{}).
    AutoCreateTable(true).
    Build()
builder.ModelGroup(analyticsGroup)

Auth and Middleware

Per-Route Metadata (WithMeta)

Tag routes declaratively — the filter checks once, not in every handler:

func (c *ApiController) Init(ctx *core.Context) error {
    // Public
    ctx.Get("/api/login", login).WithMeta(SkipAuth())

    // Requires login
    ctx.Get("/api/profile", profile).WithMeta(RequireAuth())

    // Requires login + specific permission
    ctx.Post("/api/admin/users", createUser).
        WithMeta(RequireAuth(), RequirePermission("admin:create_user"))
    return nil
}
// Define metadata factories
func RequireAuth() web.MetaOption      { return web.WithValue("require_auth", true) }
func SkipAuth() web.MetaOption          { return web.WithValue("skip_auth", true) }
func RequirePermission(p string) web.MetaOption { return web.WithValue("require_permission", p) }
// One filter handles all auth logic
func (f *AuthFilter) Handle(fc web.FilterChain, req *web.Request) (any, error) {
    if !req.HasMeta(RequireAuth()) || req.HasMeta(SkipAuth()) {
        return fc.Next()
    }

    token := req.Request().Header.Get("Authorization")
    if token == "" {
        return nil, errors.New("unauthorized")
    }

    // Verify token, check permission from meta...
    return fc.Next()
}
Global Filters

Filters registered via builder.Filter() run on every request:

// Logging
type LoggingFilter struct { core.IFilter }

func (f *LoggingFilter) Handle(fc web.FilterChain, req *web.Request) (any, error) {
    start := time.Now()
    result, err := fc.Next()
    log.Info("request", zap.String("path", req.FullPath()), zap.Duration("elapsed", time.Since(start)))
    return result, err
}

// CORS (built-in, just register it)
builder.Filter(&cors.Filter{})
RestGroup: Filters Scoped to a Route Group
apiGroup := core.NewRestGroupBuilder().
    ServerConfig(web.DefaultServerConfig()).
    ContextPath("/api/v1").
    Build()

apiGroup.AddFilter(&AuthFilter{})     // only affects routes in this group
apiGroup.AddRest(&UserController{})   // all routes in this controller need auth

builder.RestGroup(apiGroup)

Common Recipes

File Upload
ctx.Post("/upload", func(req *web.Request) (any, error) {
    file, header, err := req.File("file")   // form field name
    if err != nil {
        return nil, err
    }
    defer file.Close()

    // Save to disk
    dst := "./uploads/" + header.Filename
    if err := web.SaveUploadedFile(header, dst); err != nil {
        return nil, err
    }
    return map[string]string{"path": dst}, nil
})
WebSocket
ctx.WebSocket("/ws", func(stream *web.WebSocketStream) error {
    defer stream.Close()
    for {
        typ, msg, err := stream.Read(stream.Context())
        if err != nil {
            return err
        }
        stream.Write(stream.Context(), typ, msg)  // echo
    }
})
Server-Sent Events
ctx.SSE("/events", func(stream *web.SSEStream) error {
    defer stream.Close()
    stream.SendRetry(3000)  // reconnect after 3s

    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    for range ticker.C {
        stream.Send("update", fmt.Sprintf("time: %s", time.Now()))
    }
    return nil
})
Static Files & SPA
ctx.Static("/assets", "./public")
ctx.Static("/", "./frontend/dist")   // SPA build output
# Or via config — serves multiple directories, auto 404 fallback:
web:
  server:
    locations:
      - view/dist
      - www
    page404: 404.html
Reverse Proxy
ctx.ReverseProxy("/api/legacy", "http://127.0.0.1:8081")
Background Tasks
type CleanupTask struct { core.IRunner }

func (t *CleanupTask) Init(ctx *core.Context) error { return nil }

func (t *CleanupTask) Run() error {
    ticker := time.NewTicker(5 * time.Minute)
    defer ticker.Stop()
    for range ticker.C {
        // clean up expired sessions...
    }
    return nil  // returned error kills the runner
}

builder.Runner(&CleanupTask{})
Validation
type CreateUserInput struct {
    Name  string `validate:"required,min=2,max=50"`
    Email string `validate:"required,email"`
}

func (c *Controller) Create(req *web.Request) (any, error) {
    var input CreateUserInput
    if err := req.BindJSON(&input); err != nil {
        return nil, err
    }

    validator := wf.GetService[*validator.Validator](req.Ctx())
    if err := validator.Validate(input); err != nil {
        return nil, web.NewValidationError().WithError(err)
    }

    // input is valid, proceed...
}
Custom HTTP Response
// Return a plain struct → auto-wrapped: {"code":200, "data":{...}, "msg":"ok"}
return &User{Id: 1, Name: "alice"}, nil

// Return a string → plain text response
return "ok", nil

// Return a specific status code
return web.DataCode(http.StatusCreated, &user), nil

// Return an error
return nil, errors.New("something went wrong")

// Return a business error code
return nil, web.NewValidationError().WithDetail("name is required")

// Redirect
return web.Redirect("/new-url"), nil

// File download
return &web.FileResponse{Path: "/path/to/report.pdf", FileName: "report.pdf"}, nil

Configuration

One YAML file covers everything. Auto-loaded from ./config/, ~/.<appname>/, /etc/<appname>/.

web:
  server:
    port: 8080
    context_path: /api            # all routes prefixed with /api
    ssl:                          # HTTPS: auto-cert or local certificates
      enabled: true
      hosts:                      # Let's Encrypt auto-cert for these domains
        - example.com
      # certs:                    # Or use local certificate files (optional)
      #   - host: example.com
      #     cert-file: /path/to/fullchain.pem
      #     key-file: /path/to/privkey.pem

  db:
    type: mysql                   # mysql | postgres | sqlite
    host: localhost
    port: 3306
    user: root
    password: your_password
    database: mydb
    max_open_conns: 100
    max_idle_conns: 10
    conn_max_lifetime: 3600

  log:
    level: info                   # debug | info | warn | error
    path: ./logs/app.log
    max_size: 500                 # MB per file before rotation
    max_backups: 3
    max_age: 30                   # days
    compress: true

  redis:
    addr: localhost:6379
    password: ""
    db: 0

PostgreSQL and SQLite variants:

# PostgreSQL
db:
  type: postgres
  host: localhost
  port: 5432
  user: postgres
  password: ""
  database: mydb
  sslmode: disable

# SQLite
db:
  type: sqlite
  path: ./data.db

Format support: JSON, YAML, TOML. Call config.LoadAutoConfig() for zero-config auto-discovery, or pass a path explicitly.

Custom Database Driver

Register a custom database driver for databases not built-in (e.g., SQL Server, ClickHouse). The framework uses GORM as the underlying ORM, so custom databases must have a GORM driver.

// 1. Implement db.IConfig interface
type ClickHouseConfig struct {
    Host     string
    Port     int
    Database string
    User     string
    Password string
}

func (c *ClickHouseConfig) Connection() (*db.DB, error) {
    dsn := fmt.Sprintf("clickhouse://%s:%s@%s:%d/%s", c.User, c.Password, c.Host, c.Port, c.Database)
    gormDB, err := gorm.Open(clickhouse.Open(dsn), &gorm.Config{})
    if err != nil {
        return nil, err
    }
    return &db.DB{DB: gormDB}, nil
}

// 2. Register before app starts
func main() {
    db.RegisterDB("clickhouse", &ClickHouseConfig{})
    builder := wf.NewBuilder(config.LoadAutoConfig())
    builder.Build().Start()
}

Then configure in YAML:

web:
  db:
    type: clickhouse
    host: localhost
    port: 9000
    database: mydb

Tech Stack

Pre-integrated, production-proven components:

Layer Library Role
HTTP Gin Router, middleware chain, parameter binding
ORM GORM Underlying SQL driver, migrations, join/preload
Config Viper Multi-format, multi-path auto-loading
Logging Zap Structured, leveled, with rotation
JSON Sonic High-performance marshal/unmarshal
Cache Otter Local in-memory cache
Concurrency Conc Structured concurrency pool for server lifecycle
Redis go-redis Pub/sub, caching
SQLite modernc/sqlite Pure Go, zero CGO
Validation go-playground/validator Struct tag validation
WebSocket coder/websocket Upgrade + read/write
Cron robfig/cron Expression-based scheduler

Project Layout

├── web_frame.go        # Builder, WebFrame factory
├── core/               # Interfaces (IService, IModel, IRest, IRunner, IFilter), DI context
├── web/                # Request, response, routing, filters, SSE, WebSocket, static files
├── model/              # Model[T], EntryModel[T, PK], Query[T], Update[T], Delete[T]
├── db/                 # MySQL, PostgreSQL, SQLite connection management
├── redis/              # Redis client wrapper
├── config/             # Viper auto-loading
├── log/                # Zap + lumberjack rotation
├── component/          # cors, cache, rate-limit, captcha, qrcode, cron, validator
├── util/               # Crypto, file, string helpers
└── example/            # Runnable examples
    ├── helloworld/     # Minimal app
    ├── rest/           # REST controller
    ├── model/          # Generic ORM usage
    ├── filter/         # Auth + logging filters
    ├── withmeta/       # Route metadata
    └── background/     # Background runners

Optional Modules

Heavy dependencies are split into independent sub-modules. Install only what you need:

cache captcha schedule qrcode ratelimit

# Core framework (no captcha/qrcode/cron/otter)
go get github.com/chuccp/go-web-frame

# Optional — install as needed
go get github.com/chuccp/go-web-frame/component/captcha@v1.0.7
go get github.com/chuccp/go-web-frame/component/schedule@v1.0.7
go get github.com/chuccp/go-web-frame/component/qrcode@v1.0.7
go get github.com/chuccp/go-web-frame/component/cache@v1.0.7
go get github.com/chuccp/go-web-frame/component/ratelimit@v1.0.7
Usage
Cache — High-Performance In-Memory Cache
import "github.com/chuccp/go-web-frame/component/cache"

// 1. Register
builder.Service(&cache.Cache{})

// 2. Use in any controller or service
c := core.GetService[*cache.Cache](ctx)
c.Set("user:1", user)
val, ok := c.Get("user:1")
c.SetNX("lock:task", true, 30*time.Second) // set if not exists, with TTL
Captcha — Slide Puzzle Captcha
# application.yml
captcha:
  code_key: "your-32-character-key-here!!"  # 32 chars, required
  code_iv: "your-16-char-iv"                # 16 chars, required
import "github.com/chuccp/go-web-frame/component/captcha"

// 1. Register
builder.Service(&captcha.Captcha{})

// 2. Generate captcha (return to frontend)
c := core.GetService[*captcha.Captcha](ctx)
data, _ := c.GetCaptchaData()
// → returns SlideCaptchaData with TileImage, MasterImage, ThumbCode

// 3. Validate user's slide answer
result, ok := c.ValidateThumb(data.ThumbCode, userXOffset)
if ok {
    valid, _ := c.ValidateCode(result.CaptchaCode)
}
Schedule — Cron Job Scheduler
import (
    "github.com/chuccp/go-web-frame/component/schedule"
    "github.com/robfig/cron/v3"
)

// 1. Register as Runner (NOT Service)
sched := schedule.NewSchedule(cron.WithSeconds())
builder.Runner(sched)

// 2. Add jobs — before or after Build()
sched.AddKeyFunc("cleanup", "0 0 * * *", func(ctx *core.Context) {
    // runs daily at midnight
})
sched.AddKeyFunc("report", "*/30 * * * * *", func(ctx *core.Context) {
    // runs every 30 seconds
})
QRCode — QR Code Generator
import "github.com/chuccp/go-web-frame/component/qrcode"

// Generate to a file (stripe style)
qrcode.GenerateStripeQRCode("https://example.com", "qr.png")

// Generate in-memory with custom style
buf := qrcode.CreateBufferWriteCloser()
qrcode.GenerateQrcode("hello", buf, qrcode.WithCircleShape())
pngBytes := buf.Bytes()

// Custom colors
s := qrcode.NewStripeQRCode().WithModuleSize(10)
s.GenerateFile("https://example.com", "custom.png")

QRCode is a standalone utility — no registration needed. Just import and call directly.

RateLimit — Token-Bucket Rate Limiter
# application.yml (optional — defaults shown)
rate_limit:
  limit: 10     # tokens per second
  burst: 5      # max burst size
import "github.com/chuccp/go-web-frame/component/ratelimit"

// 1. Register
builder.Service(&ratelimit.RateLimit{})

// 2. Use — typically in a Filter
r := core.GetService[*ratelimit.RateLimit](ctx)
if r.Allow(req.ClientIP()) {
    return fc.Next()
}
return nil, errors.New("rate limited")
Publishing Sub-Modules

Each sub-module is versioned independently using tag prefixes:

# 1. Publish the main module
git tag v1.0.1
git push origin v1.0.1

# 2. Update each sub-module's dependency on the main module
for mod in captcha schedule qrcode cache ratelimit; do
  cd component/$mod
  go get github.com/chuccp/go-web-frame@v1.0.1
  go mod edit -dropreplace github.com/chuccp/go-web-frame
  go mod tidy
  cd ../..
done

# 3. Tag each sub-module (format: component/<name>/vX.Y.Z)
git tag component/captcha/v1.0.1
git tag component/schedule/v1.0.1
git tag component/qrcode/v1.0.1
git tag component/cache/v1.0.1
git tag component/ratelimit/v1.0.1

# 4. Push all tags
git push origin --tags

Go's module proxy resolves component/captcha/v1.0.1 to the component/captcha/ directory automatically.


Getting Help


Contributing

PRs welcome. Run go test ./... before submitting.

License

MIT — see LICENSE

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetFilter added in v0.1.3

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

GetFilter retrieves a filter of the specified type from the context.

func GetModel

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

GetModel retrieves a model of the specified type from the context.

func GetReNewModel

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

GetReNewModel retrieves a model and creates a fresh instance with the given database connection.

func GetRunner

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

GetRunner retrieves a runner of the specified type from the context.

func GetService

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

GetService retrieves a service of the specified type from the context.

func LoadAutoConfig

func LoadAutoConfig() *config2.Config

func LoadConfig

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

func NewModelGroupBuilder added in v0.7.2

func NewModelGroupBuilder() *core.ModelGroupBuilder

NewModelGroupBuilder creates a new model group builder from the core package.

func NewRestGroupBuilder added in v0.7.2

func NewRestGroupBuilder() *core.RestGroupBuilder

NewRestGroupBuilder creates a new REST group builder from the core package.

func UnmarshalKeyConfig added in v0.1.3

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

UnmarshalKeyConfig unmarshals configuration under the given key into the specified type.

Types

type Builder added in v0.7.1

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

Builder provides a fluent API for constructing a WebFrame application. Register routes, REST controllers, models, services, filters, and runners, then call Build() to create the application.

func NewBuilder added in v0.7.1

func NewBuilder(config config2.IConfig) *Builder

NewBuilder creates a new Builder with the given configuration for constructing a WebFrame.

func (*Builder) Any added in v0.7.1

func (b *Builder) Any(relativePath string, handlers ...web.HandlerFunc) *Builder

Any registers a route handler for all HTTP methods and returns the builder for chaining.

func (*Builder) Build added in v0.7.1

func (b *Builder) Build() *WebFrame

Build creates a WebFrame from the builder configuration. The returned application can be started with Run or Test.

func (*Builder) Delete added in v0.7.1

func (b *Builder) Delete(relativePath string, handlers ...web.HandlerFunc) *Builder

Delete registers a DELETE route handler and returns the builder for chaining.

func (*Builder) Filter added in v0.7.1

func (b *Builder) Filter(filters ...core.IFilter) *Builder

Filter registers one or more filters and returns the builder for chaining.

func (*Builder) Get added in v0.7.1

func (b *Builder) Get(relativePath string, handlers ...web.HandlerFunc) *Builder

Get registers a GET route handler and returns the builder for chaining.

func (*Builder) Model added in v0.7.1

func (b *Builder) Model(model ...core.IModel) *Builder

Model registers one or more models and returns the builder for chaining.

func (*Builder) ModelGroup added in v0.7.1

func (b *Builder) ModelGroup(modelGroups ...core.IModelGroup) *Builder

ModelGroup registers one or more model groups and returns the builder for chaining.

func (*Builder) Post added in v0.7.1

func (b *Builder) Post(relativePath string, handlers ...web.HandlerFunc) *Builder

Post registers a POST route handler and returns the builder for chaining.

func (*Builder) Put added in v0.7.1

func (b *Builder) Put(relativePath string, handlers ...web.HandlerFunc) *Builder

Put registers a PUT route handler and returns the builder for chaining.

func (*Builder) Rest added in v0.7.1

func (b *Builder) Rest(rest ...core.IRest) *Builder

Rest registers one or more REST controllers and returns the builder for chaining.

func (*Builder) RestGroup added in v0.7.1

func (b *Builder) RestGroup(restGroups ...*core.RestGroup) *Builder

RestGroup registers one or more REST groups and returns the builder for chaining.

func (*Builder) Runner added in v0.7.1

func (b *Builder) Runner(runner ...core.IRunner) *Builder

Runner registers one or more background runners and returns the builder for chaining.

func (*Builder) Service added in v0.7.1

func (b *Builder) Service(service ...core.IService) *Builder

Service registers one or more services and returns the builder for chaining.

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
}

WebFrame is the main application struct that holds all components, services, models, REST groups, and configuration for a web application.

func (*WebFrame) GetHandler added in v1.0.11

func (w *WebFrame) GetHandler() http.Handler

func (*WebFrame) Run added in v0.1.3

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

Run initializes the logger, sets up all components, services, models, and REST groups, then starts the HTTP servers and background runners. The provided context controls the application lifecycle for graceful shutdown.

func (*WebFrame) Start

func (w *WebFrame) Start() error

Start initializes and runs the web application with a background context. Blocks until the application is shut down.

func (*WebFrame) Test added in v0.5.1

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

Test initializes the application without starting a real HTTP server, allowing tests to run against the initialized context.

Directories

Path Synopsis
component
auth module
cache module
captcha module
cors module
localcache module
qrcode module
ratelimit module
schedule module
validator module
建议:不要直接使用本包中的 db.DB / db.Table 操作数据库,推荐使用 model.EntryModel 或 model.Model, 它们提供了类型安全、更高层级的 CRUD 封装,代码更简洁且不易出错。
建议:不要直接使用本包中的 db.DB / db.Table 操作数据库,推荐使用 model.EntryModel 或 model.Model, 它们提供了类型安全、更高层级的 CRUD 封装,代码更简洁且不易出错。
example
background command
config command
filter command
helloworld command
middleware command
rest command
websocket-sse command
withmeta command
Package web: server configuration types and defaults.
Package web: server configuration types and defaults.

Jump to

Keyboard shortcuts

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