GoOmni
GoOmni 是一套面向业务复用的 Go 后端基础框架。当前默认用 Gin 作为网络适配器,业务代码只依赖 GoOmni 的 transport-neutral API,后续可以替换为自研网络层。
远程 module 地址是 git.yuntuo.hk/k2safe/go-omni。业务项目可以直接引用指定版本:
go get git.yuntuo.hk/k2safe/go-omni@v0.2.0
创建新业务项目:
go install git.yuntuo.hk/k2safe/go-omni/cmd/go-omni@v0.2.0
go-omni new --module example.com/billing ./billing
cd billing
go mod tidy
go run ./cmd/server
远程安装的 CLI 默认引用自身版本,生成的项目不需要本地 replace。
具体版本和本地开发选项见 CLI 文档。
需要数据库持久化时,使用 go-omni new --database mysql --module example.com/billing ./billing。
生成项目包含完整用户 CRUD、数据库 Repository、ServiceContext、建表脚本和就绪探针。
先应用生成的 schema.sql,再配置 GO_OMNI_DB_DSN;启动时会检查连接与表结构,退出时释放连接池。
目录结构
go-omni/
├── app/ # 应用启动和生命周期
├── httpx/ # 与网络框架无关的 HTTP 抽象
├── response/ # 统一响应
├── errors/ # 统一错误
├── health/ # 存活和就绪检查
├── middleware/ # 请求 ID 等基础中间件
├── logx/ # 业务层结构化日志
├── config/ # 配置管理
├── validate/ # 参数校验
├── auth/ # 认证和权限接口
├── database/ # database/sql 生命周期和事务
├── transport/gin/ # Gin 网络适配器,可替换
├── examples/ # 示例项目
└── cmd/ # go-omni 项目脚手架
快速开始
package main
import omni "git.yuntuo.hk/k2safe/go-omni"
func main() {
app := omni.New()
app.GET("/health", func(ctx *omni.Context) error {
return ctx.OK(map[string]string{"status": "ok"})
})
app.Run(":8080")
}
成功响应默认使用统一结构:
{
"code": "OK",
"message": "success",
"data": {"status": "ok"},
"requestId": "..."
}
业务错误可以直接返回:
return omni.NotFound("USER_NOT_FOUND", "user was not found")
默认 Gin 适配器位于 transport/gin。业务层不需要导入 Gin;如果后续实现自己的网络层,只需要实现 httpx.Router / httpx.RouterGroup,然后通过 omni.NewWithRouter 启动应用:
application := omni.NewWithRouter(myRouter)
仓库还提供了只依赖标准库的 transport/nethttp 参考实现,可以直接验证这条替换路径。
app.Engine() 现在返回标准 http.Handler,ctx.Raw() 返回适配器提供的 http.ResponseWriter,避免业务 API 锁定 Gin 类型。
业务代码可以直接使用 git.yuntuo.hk/k2safe/go-omni/logx 打结构化日志,不需要依赖 Gin:
func (s *UserService) Create(ctx *httpx.Context) error {
logx.InfoContext(ctx.Context(), "user.create", "email", input.Email)
return nil
}
WithLogger(true) 会启用 GoOmni 的统一 HTTP 访问日志;日志内容和业务日志共用 requestId。应用启动时可以调用 logx.Setup 配置 JSON/文本格式、级别、服务名和输出文件。
应用配置可以统一从 GO_OMNI_* 环境变量加载,再交给 omni.New:
settings, err := omni.LoadConfig("")
if err != nil {
log.Fatal(err)
}
logger, err := logx.New(settings.Log)
if err != nil {
log.Fatal(err)
}
application := omni.New(omni.WithConfig(settings))
application.OnShutdown(logger.Close)
常用变量包括 GO_OMNI_ENABLE_LOGGER、GO_OMNI_LOG_LEVEL、
GO_OMNI_LOG_FORMAT、GO_OMNI_LOG_OUTPUT、GO_OMNI_SERVICE、
GO_OMNI_ENVIRONMENT、GO_OMNI_HTTP_ADDR 和 GO_OMNI_SHUTDOWN_TIMEOUT。数据库连接仍由
database.ConfigFromEnv 从 GO_OMNI_DB_* 加载。
App 同时实现标准 http.Handler。Run 监听 SIGINT / SIGTERM;RunContext 则由调用方的 context 控制退出,生成项目已使用 signal.NotifyContext 接好信号。
退出时先停止接收新请求,等待活跃请求完成,再执行资源清理。超过 ShutdownTimeout 时强制关闭连接、取消请求 context,并返回超时错误。业务代码应响应 context 取消;框架无法强制结束忽略取消的业务 goroutine。数据库连接池由 database.Open 创建,在服务退出时调用 Close。
应用资源可以直接挂到 omni.New 返回的生命周期上:
application := omni.New()
application.OnShutdown(db.Close)
清理函数会按注册顺序的逆序执行,application.Close() 和 RunContext 都会触发,且重复调用安全。
服务可以把数据库、缓存等依赖注册为就绪探针:
checker, err := health.New(health.Probe{
Name: "database",
Check: db.PingContext,
})
if err != nil {
log.Fatal(err)
}
application.GET("/health/live", checker.LivenessHandler())
application.GET("/health/ready", checker.ReadinessHandler())
存活检查只确认进程在线;就绪检查会执行全部探针,任意依赖失败时返回 HTTP 503。
新项目脚手架会生成项目自己的 internal/servicecontext。它集中保存 Logger、数据库、缓存和外部客户端,Service 只依赖这个项目上下文,不把基础设施初始化散落到各个 Handler:
services, err := servicecontext.New(ctx, logger)
if err != nil {
return err
}
defer services.Close()
userService := service.NewUsers(services)
完整业务参考项目
examples/reference 提供按 Handler / Service / Repository / Model 分层的用户 CRUD 示例。默认使用并发安全的内存存储,支持分页、邮箱唯一校验、结构化请求日志和统一错误,无需配置数据库。
在框架根目录运行:
go run ./examples/reference
默认地址为 http://127.0.0.1:8080。示例文档提供完整的 curl 操作流程。数据只保存在内存中,重启后清空。
框架的 App 也实现了标准 http.Handler,可以直接用于 http.Server 和 httptest.NewServer;业务路由可通过 *omni.RouterGroup 注册,无需导入 Gin。
当前边界
缓存、消息队列和定时任务暂时作为后续可选模块。认证层只定义 Authenticator、Principal 和路由保护中间件,具体 JWT、Session 或 OAuth 由项目实现。核心数据库层只依赖 database/sql,具体驱动、迁移和表结构由项目选择。
当前成熟度与后续验收标准见 ROADMAP.md,版本变更见 CHANGELOG.md。