2026-04-25 13:26:02 +08:00
2026-04-25 13:26:02 +08:00
2026-08-09 01:06:21 +08:00
2026-08-09 01:06:21 +08:00
2026-08-09 01:13:58 +08:00

Go Skeleton

面向实际项目开发的 Go Web API 脚手架。它将 HTTP、WebSocket、认证、数据库迁移、缓存、接口文档和可观测性组织成可继续扩展的基础工程。

当前模块名为 skeleton。创建新项目后,请先使用初始化脚本替换成自己的 Go module path。

特性

  • Gin HTTP 路由及公开、JWT 私有路由分组
  • PostgreSQL、MySQL、SQLite 三种 GORM 数据库驱动
  • 按 SQL 方言隔离的 Atlas 数据库迁移
  • 可选 Redis,以及 JWT 撤销记录存储
  • Access Token、Refresh Token、刷新轮换和注销示例
  • WebSocket 房间、广播、连接管理和心跳示例
  • Swaggo OpenAPI 文档和 Swagger UI
  • Zap 结构化日志、请求 ID、Prometheus 指标
  • OpenTelemetry OTLP HTTP 链路追踪
  • Dockerfile、Docker Compose、GitHub Actions
  • Linux、macOS、Windows amd64 交叉编译

目录

技术栈

能力 实现
HTTP Gin
WebSocket Gorilla WebSocket
ORM GORM
数据库 PostgreSQL / MySQL / SQLite
数据迁移 Atlas + Atlas GORM Provider
缓存 Redis,可选
认证 JWT HS256 + bcrypt
API 文档 Swaggo / Swagger UI
日志 Zap
指标 Prometheus
Trace OpenTelemetry OTLP HTTP

快速开始

环境要求

  • Go 1.25+
  • Atlas CLI,仅执行数据库迁移时需要
  • Swag CLI,仅重新生成 OpenAPI 文档时需要
  • Docker,可选
  • C 编译器,使用 SQLite 时需要

1. 创建自己的项目

git clone https://gitea.xchoumc.online/xchou/go-skeleton.git
cd go-skeleton
./scripts/init.sh github.com/yourname/your-project

2. 使用 SQLite 快速运行

修改 config/app.yaml

database:
  driver: sqlite
  sqlite_path: data/skeleton.db

redis:
  enabled: false

应用迁移:

export DATABASE_URL='sqlite://data/skeleton.db'
export DATABASE_DEV_URL='sqlite://dev?mode=memory&_fk=1'
go run cmd/migrate/main.go -action apply

启动服务:

go run .

默认服务地址:

服务 地址
API http://localhost:8080/api
Swagger UI http://localhost:8080/docs/index.html
Prometheus Metrics http://localhost:8080/metrics
WebSocket ws://localhost:8080/api/ws

项目结构

.
├── main.go                     # 应用启动与优雅关闭
├── config/                     # YAML、环境变量及配置校验
├── database/                   # GORM、Redis、Token 撤销和迁移封装
├── middlewares/                # JWT、日志、CORS、指标、Request ID
├── models/                     # GORM 数据模型
├── modules/
│   ├── auth/                   # 注册、登录、刷新和注销示例
│   ├── example/                # REST 业务模块示例
│   └── ws/                     # WebSocket Hub、Client 和消息协议
├── observability/              # OpenTelemetry 初始化
├── routes/
│   ├── rest/                   # REST 路由注册器
│   └── ws/                     # WebSocket 路由挂载
├── docs/                       # Swag 自动生成文件
├── migrations/
│   ├── postgres/
│   ├── mysql/
│   └── sqlite/
├── tools/atlas-loader/         # 独立 Atlas GORM Schema 工具模块
├── scripts/
│   ├── init.sh                 # 修改 Go module path
│   └── build.sh                # 多平台 amd64 构建
├── Dockerfile
├── docker-compose.yml
└── Makefile

配置

应用默认读取 config/app.yaml。使用其他配置文件:

export SKELETON_CONFIG=config/app.yaml

环境变量优先级高于 YAML。生产环境应使用部署平台的 Secret 管理能力注入凭据。

应用和日志

环境变量 说明
APP_HOSTAPP_PORT HTTP 监听地址
APP_VERSION 应用版本
APP_ENVIRONMENT developmentproduction
APP_DEBUG Gin 调试模式
APP_TIMEZONE IANA 时区名称
LOG_LEVEL debuginfowarnerror
LOG_FORMAT consolejson
LOG_OUTPUT stdoutfile

数据库

环境变量 说明
DATABASE_DRIVER postgresmysqlsqlite
DATABASE_DSN 完整连接串,优先于其他连接参数
DATABASE_HOSTDATABASE_PORT 服务端数据库地址
DATABASE_USERNAMEDATABASE_PASSWORD 数据库凭据
DATABASE_NAME 数据库名称
DATABASE_SSLMODE PostgreSQL SSL 模式
DATABASE_SQLITE_PATH SQLite 文件路径
DATABASE_MAX_IDLE_CONNS 最大空闲连接数
DATABASE_MAX_OPEN_CONNS 最大连接数
DATABASE_CONN_MAX_LIFETIME 连接最大存活分钟数

未设置 database.driver 时默认使用 PostgreSQL。SQLite 会创建数据文件父目录,并默认限制为单连接。

Redis、JWT 和可观测性

环境变量 说明
REDIS_ENABLED 是否启用 Redis
REDIS_HOSTREDIS_PORTREDIS_PASSWORD Redis 连接信息
JWT_SECRET HS256 签名密钥
JWT_ACCESS_EXPIRE_MINUTES Access Token 有效分钟数
JWT_REFRESH_EXPIRE_HOURS Refresh Token 有效小时数
METRICS_ENABLEDMETRICS_PATH Prometheus 指标开关和路径
TRACING_ENABLED 是否启用 OpenTelemetry
OTEL_SERVICE_NAME Trace 服务名
OTEL_EXPORTER_OTLP_ENDPOINT OTLP HTTP 地址,如 localhost:4318
OTEL_EXPORTER_OTLP_INSECURE 是否使用明文 OTLP

生产模式会拒绝默认或少于 32 个字符的 JWT 密钥。

HTTP API

方法 路径 认证 说明
GET /api/ping 进程存活检查
GET /api/health 数据库和可选 Redis readiness 检查
GET /api/example/hello REST 模块示例
POST /api/auth/register 注册示例用户
POST /api/auth/login 获取 Token Pair
POST /api/auth/refresh 轮换 Refresh Token
POST /api/private/auth/logout Bearer 撤销 Access/Refresh Token
GET /api/ws WebSocket 握手入口

完整请求和响应模型请查看 Swagger UI。

响应约定

业务接口统一使用 HTTP 200 返回结果,业务状态通过响应体中的 code 字段表达,不使用 HTTP 状态码传递业务成功或失败状态。

{
  "code": 401,
  "message": "用户名或密码错误",
  "data": null
}

统一响应结构:

字段 说明
code 业务状态码,例如 200400401409500
message 面向调用方的结果说明
data 业务数据;失败时通常为 null

新增业务接口时必须遵守以下约定:

  • HTTP 响应状态固定为 200 OK
  • 成功使用响应体 code: 200
  • 参数、认证、权限和业务冲突等错误写入响应体 code
  • 调用方应判断响应体中的 code,不能依赖 HTTP 状态码判断业务结果。
  • WebSocket 握手、协议升级失败以及基础设施健康检查不属于普通业务响应,可以使用对应的 HTTP 状态码。

认证示例

curl -X POST http://localhost:8080/api/auth/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"demo","password":"change-me-123"}'

curl -X POST http://localhost:8080/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"demo","password":"change-me-123"}'

启用 Redis 时,Token 撤销记录存储在 Redis,适合多实例部署;关闭 Redis 时使用进程内存,仅适合开发或单实例部署。

WebSocket

连接端点:

ws://localhost:8080/api/ws?room=lobby&client_id=demo

查询参数:

参数 必填 说明
room 房间名,默认 lobby,最多 64 个字符
client_id 客户端标识;未提供时服务端生成

使用 websocat

websocat 'ws://localhost:8080/api/ws?room=lobby&client_id=terminal-1'

发送消息:

{"type":"message","data":"hello websocket"}

服务端事件:

{
  "type": "message",
  "room": "lobby",
  "client_id": "terminal-1",
  "data": "hello websocket",
  "timestamp": "2026-08-09T00:00:00Z"
}

事件类型:

类型 说明
welcome 当前客户端连接成功
message 房间广播消息
presence 客户端加入或离开
error 消息格式或类型错误

浏览器示例:

const socket = new WebSocket(
  "ws://localhost:8080/api/ws?room=lobby&client_id=browser-1"
);

socket.onmessage = (event) => console.log(JSON.parse(event.data));
socket.onopen = () => {
  socket.send(JSON.stringify({ type: "message", data: "hello" }));
};

WebSocket 实现包含:

  • 按房间隔离广播
  • 在线连接数量
  • 单连接一个 reader 和一个 writer
  • Ping/Pong 心跳与读取超时
  • 8 KiB 单消息限制
  • 有界发送队列和慢客户端清理
  • 安全的默认同源 Origin 校验

当前 Hub 是单进程内存实现。多实例部署时,应在 modules/ws/hub.go 接入 Redis Pub/Sub、NATS 或其他消息系统。

数据库迁移

安装 Atlas

brew install ariga/tap/atlas
# 或
go install ariga.io/atlas/cmd/atlas@latest

设置当前数据库和开发数据库 URL

# PostgreSQL
export DATABASE_URL='postgres://user:pass@localhost:5432/app?sslmode=disable'
export DATABASE_DEV_URL='docker://postgres/17/dev'

# MySQL
export DATABASE_URL='mysql://user:pass@localhost:3306/app'
export DATABASE_DEV_URL='docker://mysql/8/dev'

# SQLite
export DATABASE_URL='sqlite://data/app.db'
export DATABASE_DEV_URL='sqlite://dev?mode=memory&_fk=1'

常用命令:

# 状态
go run cmd/migrate/main.go -action status

# 根据 GORM 模型生成迁移
go run cmd/migrate/main.go -action diff -name add_orders

# 校验
go run cmd/migrate/main.go -action validate

# 预览
go run cmd/migrate/main.go -action apply -dry-run

# 应用
go run cmd/migrate/main.go -action apply

# 显式选择 Atlas 环境
go run cmd/migrate/main.go -action status -env local_mysql

迁移工具会根据 app.environmentdatabase.driver 自动选择对应的 Atlas 环境。三种数据库的迁移文件不可混用。

接口文档

安装 Swag 并重新生成:

go install github.com/swaggo/swag/cmd/swag@v1.8.12
swag init

生成文件位于 docs/,应用运行时不依赖 Swag CLI。

可观测性

  • GET /api/pingliveness,不访问外部服务
  • GET /api/healthreadiness,依赖异常时返回 HTTP 503
  • GET /metricsPrometheus Counter 和 Histogram
  • X-Request-ID:接收上游 ID 或自动生成,并写入响应和日志
  • OpenTelemetry:启用后通过 OTLP HTTP 导出 Gin 请求 Span

Docker Compose 默认提供 Jaeger UIhttp://localhost:16686

测试

单元测试和静态检查:

go test ./...
go test -race ./config ./database ./middlewares ./modules/ws
go vet ./...

PostgreSQL 和 MySQL 集成测试:

export TEST_POSTGRES_DSN='postgres://skeleton:skeleton@127.0.0.1:5432/skeleton?sslmode=disable'
export TEST_MYSQL_DSN='skeleton:skeleton@tcp(127.0.0.1:3306)/skeleton?charset=utf8mb4&parseTime=True&loc=Local'
go test -tags=integration ./database

Makefile 快捷命令:

make test
make vet
make integration

编译

当前平台无 CGO 构建:

make build

Linux、macOS、Windows x64/amd64 交叉编译:

CGO_ENABLED=0 GOOS=linux   GOARCH=amd64 go build -o dist/skeleton-linux-amd64 .
CGO_ENABLED=0 GOOS=darwin  GOARCH=amd64 go build -o dist/skeleton-darwin-amd64 .
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o dist/skeleton-windows-amd64.exe .

项目封装命令:

VERSION=0.1.0 make build-x64

SQLite 官方驱动依赖 CGO。跨平台 CGO_ENABLED=0 产物支持 PostgreSQL 和 MySQLSQLite 应在目标平台原生构建:

make build-native

Docker

默认启动应用、PostgreSQL、Redis、Atlas 迁移和 Jaeger

docker compose up --build

额外启动 MySQL

docker compose --profile mysql up -d mysql

停止:

docker compose down

删除本地 Compose 数据卷:

docker compose down -v

开发新模块

推荐结构:

modules/order/
├── controller.go
├── service.go
├── types.go
└── repository.go

开发流程:

  1. modules/ 添加业务代码。
  2. routes/rest/ 注册公开或 JWT 私有路由。
  3. models/ 添加或修改 GORM 模型。
  4. 为目标数据库分别生成和检查 Atlas 迁移。
  5. 添加单元测试和必要的集成测试。
  6. 更新 Swag 注解并执行 swag init

安全说明

该仓库是脚手架,不应在未经审查的情况下直接用于生产:

  • 必须修改默认 JWT 密钥和示例数据库密码。
  • 根据实际前端域名收紧 CORS 和 WebSocket Origin 策略。
  • 示例注册接口应增加邀请码、管理员权限或在生产环境关闭。
  • 多实例 Token 撤销必须启用 Redis。
  • 多实例 WebSocket 广播必须接入外部消息系统。
  • TLS 应由网关、Ingress 或应用部署环境终止。

请通过私有渠道报告安全问题,不要在公开 Issue 中提交密钥或可利用细节。

贡献

欢迎提交 Issue 和 Pull Request。提交前请至少执行:

go fmt ./...
go test ./...
go vet ./...

建议每个 Pull Request 聚焦一个主题,并同步更新测试、迁移和文档。

License

当前仓库尚未包含许可证文件。正式公开分发前,请由项目维护者选择并添加合适的开源许可证。

S
Description
No description provided
Readme 175 KiB
Languages
Go 93.6%
Shell 2.8%
HCL 2.3%
Makefile 0.7%
Dockerfile 0.6%