基于 Echo、GORM、Viper、Wire、Cobra 的 HTTP 快速开发框架
EchoHub 是一个生产级的 Go HTTP 服务快速开发框架,提供了完整的分层架构、依赖注入、响应封装、中间件、日志系统和 Swagger 文档等企业级特性。
- 分层架构: 清晰的 MVC 分层设计 (Handler -> Service -> Data)
- 依赖注入: 使用 Google Wire 自动生成依赖注入代码
- 响应封装: Execute 模式统一处理响应和错误
- 中间件系统: 内置日志、恢复、JWT 认证中间件
- 双日志系统: Web 日志 + ORM 日志,支持 Debug/Release 模式
- 配置管理: 基于 Viper,支持嵌入式配置和外部配置覆盖
- CLI/TUI: 基于 Cobra 的命令行工具和交互式界面
- Swagger 文档: 自动生成 API 文档
- JWT 认证: 内置用户认证和授权
EchoHub/
├── cmd/ # CLI 命令入口
│ ├── init.go # 命令初始化
│ └── root.go # 根命令定义
├── configs/ # 外部配置文件
│ ├── debug-config.yaml # Debug 模式配置
│ └── production-config.yaml # 生产环境配置
├── internal/
│ ├── cli/ # CLI/TUI 逻辑
│ ├── config/ # 配置管理
│ ├── data/ # 数据访问层 (Repository)
│ ├── di/ # 依赖注入 (Wire)
│ ├── handler/ # HTTP 处理器 (Controller)
│ ├── middleware/ # 中间件
│ ├── model/ # 数据模型
│ ├── response/ # 响应封装
│ ├── router/ # 路由配置
│ ├── server/ # HTTP 服务器
│ ├── service/ # 业务逻辑层
│ ├── swagger/ # Swagger 文档
│ ├── tui/ # TUI 界面
│ └── util/ # 工具函数
├── main.go # 程序入口
├── Makefile # 构建脚本
└── go.mod # Go 模块定义
EchoHub 的核心设计模式是 Execute 包装器,它统一处理 HTTP 响应和错误:
import res "github.com/HoronLee/EchoHub/internal/response"
func (h *UserHandler) Register() echo.HandlerFunc {
return res.Execute(func(ctx echo.Context) res.Response {
var req user.RegisterRequest
if err := ctx.Bind(&req); err != nil {
return res.Response{Msg: "Invalid request body", Err: err}
}
if err := h.svc.Register(ctx.Request().Context(), req); err != nil {
return res.Response{Msg: "Registration failed", Err: err}
}
return res.Response{
Data: map[string]any{"message": "User registered successfully"},
Msg: "success",
}
})
}Response 结构:
Code: 自定义业务状态码 (0 表示成功)Data: 响应数据Msg: 响应消息Err: 错误信息 (不序列化到 JSON)
使用 Google Wire 自动管理依赖关系:
// internal/di/wire.go
//go:build wireinject
// +build wireinject
func InitServer(cfg *config.AppConfig) (*server.HTTPServer, func(), error) {
wire.Build(
util.NewLogger,
data.ProviderSet,
service.ProviderSet,
handler.ProviderSet,
server.ProviderSet,
)
return nil, nil, nil
}运行 make wire 生成 wire_gen.go。
Request -> Middleware -> Router -> Handler -> Service -> Data -> Database
| | | | |
v v v v v
Logger Execute Business Repository GORM
Recovery Response Logic
JWT
# 安装 Swagger 和 Wire 工具
make swagger-install
# 整理 Go 依赖
make deps编辑 configs/debug-config.yaml:
server:
port: "8080"
host: "0.0.0.0"
mode: "debug"
database:
type: "mysql" # 或 "sqlite"
source: "user:password@tcp(localhost:3306)/echohub?charset=utf8mb4&parseTime=True"
logmode: "debug"
auth:
jwt:
secret: "your-secret-key"
expires: 86400 # 24小时# 启动开发服务器
make dev
# 生成 Swagger 文档
make swagger
# 生成 Wire 代码
make wire
# 构建二进制文件
make build启动服务后访问: http://localhost:8080/api/v1/swagger/
以添加"用户资料"功能为例:
// internal/model/user/profile.go
package user
type Profile struct {
ID uint `json:"id" gorm:"primaryKey"`
UserID uint `json:"user_id" gorm:"uniqueIndex"`
Nickname string `json:"nickname" gorm:"size:50"`
Bio string `json:"bio" gorm:"size:500"`
}
type ProfileResponse struct {
Nickname string `json:"nickname" example:"张三"`
Bio string `json:"bio" example:"全栈开发者"`
}
type UpdateProfileRequest struct {
Nickname string `json:"nickname" binding:"required,min=1,max=50" example:"张三"`
Bio string `json:"bio" binding:"max=500" example:"全栈开发者"`
}// internal/data/user.go
func (d *Data) GetProfileByUserID(ctx context.Context, userID uint) (*user.Profile, error) {
var profile user.Profile
err := d.db.Where("user_id = ?", userID).First(&profile).Error
if err != nil {
return nil, err
}
return &profile, nil
}
func (d *Data) UpdateProfile(ctx context.Context, userID uint, nickname, bio string) error {
return d.db.Where("user_id = ?", userID).
Updates(&user.Profile{Nickname: nickname, Bio: bio}).Error
}// internal/service/user.go
func (s *UserService) GetProfile(ctx context.Context, userID uint) (*user.ProfileResponse, error) {
profile, err := s.data.GetProfileByUserID(ctx, userID)
if err != nil {
return nil, err
}
return &user.ProfileResponse{
Nickname: profile.Nickname,
Bio: profile.Bio,
}, nil
}
func (s *UserService) UpdateProfile(ctx context.Context, userID uint, req user.UpdateProfileRequest) error {
return s.data.UpdateProfile(ctx, userID, req.Nickname, req.Bio)
}// internal/handler/user.go
// GetProfile 获取用户资料
// @Summary 获取用户资料
// @Description 获取当前登录用户的资料信息
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} user.ProfileResponse "获取成功"
// @Failure 400 {object} res.Response "请求失败"
// @Router /user/profile [get]
func (h *UserHandler) GetProfile() echo.HandlerFunc {
return res.Execute(func(ctx echo.Context) res.Response {
userID := ctx.Get("user_id").(uint)
profile, err := h.svc.GetProfile(ctx.Request().Context(), userID)
if err != nil {
return res.Response{Msg: "Failed to get profile", Err: err}
}
return res.Response{Data: profile, Msg: "success"}
})
}
// UpdateProfile 更新用户资料
// @Summary 更新用户资料
// @Description 更新当前登录用户的资料信息
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body user.UpdateProfileRequest true "更新资料请求"
// @Success 200 {object} map[string]string "更新成功"
// @Failure 400 {object} res.Response "请求失败"
// @Router /user/profile [put]
func (h *UserHandler) UpdateProfile() echo.HandlerFunc {
return res.Execute(func(ctx echo.Context) res.Response {
userID := ctx.Get("user_id").(uint)
var req user.UpdateProfileRequest
if err := ctx.Bind(&req); err != nil {
return res.Response{Msg: "Invalid request", Err: err}
}
if err := h.svc.UpdateProfile(ctx.Request().Context(), userID, req); err != nil {
return res.Response{Msg: "Update failed", Err: err}
}
return res.Response{Msg: "Profile updated successfully"}
})
}// internal/router/user.go
func setupV1UserRoutes(routerGroup *VersionedRouterGroup, h *handler.Handlers) {
// 公开路由
routerGroup.PublicRouter.POST("/register", h.UserHandler.Register())
routerGroup.PublicRouter.POST("/login", h.UserHandler.Login())
// 需要认证的路由
routerGroup.PrivateRouter.DELETE("/user", h.UserHandler.DeleteUser())
routerGroup.PrivateRouter.GET("/user/profile", h.UserHandler.GetProfile())
routerGroup.PrivateRouter.PUT("/user/profile", h.UserHandler.UpdateProfile())
}// internal/handler/handler.go
var ProviderSet = wire.NewSet(
NewUserHandler,
NewHelloWorldHandler,
)# 生成 Swagger 文档
make swagger
# 生成 Wire 代码
make wire
# 启动开发服务器
make dev// internal/middleware/custom.go
func CustomMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
// 前置处理
log.Info("Request received")
// 调用下一个处理器
err := next(ctx)
// 后置处理
log.Info("Request completed")
return err
}
}
}
// 在 server/http.go 中使用
e.Use(middleware.CustomMiddleware())# 启动 HTTP 服务
./bin/echohub serve -c configs/debug-config.yaml
# 启动 TUI 界面
./bin/echohub tui
# 查看版本
./bin/echohub version
# 查看信息
./bin/echohub info
# 显示 Logo
./bin/echohub hello成功响应:
{
"code": 0,
"data": { ... },
"msg": "success"
}错误响应:
{
"code": 0,
"data": null,
"msg": "error message"
}使用 Bearer Token 认证:
Authorization: Bearer <your-jwt-token>
JWT_SECRET: JWT 签名密钥 (优先级高于配置文件)
# 构建生产版本
make build-prod
# 运行
./bin/echohub-prod serve -c configs/production-config.yaml| 组件 | 技术 | 说明 |
|---|---|---|
| Web 框架 | Echo | 高性能 Go Web 框架 |
| ORM | GORM | Go ORM 库 |
| 配置管理 | Viper | 配置文件管理 |
| 依赖注入 | Wire | 编译时依赖注入 |
| CLI 框架 | Cobra | 命令行工具 |
| 日志 | Zap | 结构化日志 |
| API 文档 | Swaggo | Swagger 自动生成 |
MIT License
欢迎提交 Issue 和 Pull Request!