Skip to content

gin + viper + gorm + jwt + casbin实现的golang后台API开发脚手架

License

Notifications You must be signed in to change notification settings

linclin/go-gin-rest-api

Repository files navigation

go-gin-rest-api

gin + viper + gorm + jwt + casbin实现的golang后台API开发脚手架

Go version Gin version Gorm version

配套前端ice-antd

主要功能

  • 基于Gin框架开发的REST API
  • API使用JWT的Token认证和Casbin的接口ACL、RBAC权限控制
  • 使用rql资源查询语言,支持功能更丰富的数据查询接口
  • MySQL数据库使用Gorm支持,使用gorm2-loggable插件实现数据变更记录表
  • 配置文件管理使用Viper进行,配置文件变更热加载,无需重启应用(框架基础http服务、日志、数据库不变,仅针对业务配置生效)
  • 定时任务使用robfig/cron运行,使用基于MySQL唯一索引的分布式锁避免多副本重复执行,并记录任务执行状态到数据表
  • 日志输出使用Golang 1.21版本日志库slog,搭配lumberjack日志文件切割
  • 全局panic日志输出设置使用Golang 1.23版本debug.SetCrashOutput,最低运行版本为1.23
  • 前后台对接Casdoor实现SSO单点登录,可支持LDAP、AD、企业微信、钉钉等登录

使用golang大众开源类库

  • gin 一款高效的golang web框架 教程
  • gorm 数据库ORM管理框架, 可自行扩展多种数据库类型 教程
  • rql 用于REST的资源查询语言,作为http请求和orm之间的连接器,gin和gorm的连接器
  • viper 配置管理工具, 支持多种配置文件类型.教程
  • jwt JWT token中间件
  • casbin 基于角色的访问控制模型(RBAC) 教程
  • validator 请求参数校验, 版本V10. 教程
  • lumberjack 日志切割工具, 高效分离大日志文件, 按日期保存文件
  • cast 一个小巧、实用的类型转换库,用于将一个类型转为另一个类型 教程
  • go-cache 缓存库 教程
  • resty Go的简单HTTP和REST请求客户端 教程
  • cron 实现了 cron 规范解析器和任务运行器,简单来讲就是包含了定时任务所需的功能 教程
  • lo 基于泛型实现的Golang工具库

感谢Go 每日一库提供的详细教程

gin中间件

  • appleboy/gin-jwt 权限认证中间件 -- 处理登录、登出、无状态token校验
  • casbincasbin/gorm-adapter权限访问中间件 -- 基于Cabin RBAC, 对不同角色访问不同API进行校验
  • sentinel sentinel流量控制中间件 -- api流量控制和熔断降级
  • gin-contrib/requestid requestid中间件 -- 接口trace id,每次api请求均会生成唯一id返回客户端,并保存数据库接口日志表
  • gin-contrib/cors cors跨域中间件-- 所有请求均可跨域访问
  • gin-contrib/gzip gzip中间件-- 所有API返回均进行压缩
  • gin-contrib/pprof pprof中间件
  • zsais/go-gin-prometheus prometheus中间件
  • swaggo/gin-swagger swagger中间件
  • Exception 全局异常处理中间件 -- 使用golang recover特性, 捕获所有异常, 保存到日志, 方便追溯
  • AccessLog 请求日志中间件 -- 每次请求的路由、IP自动写入日志

接口使用指南

  • golang客户端示例代码参见client目录,使用restygo-cache编写

  • 1.获取JWT生成的token(2小时超时),AppId和AppSecret存放SysSystem模型

curl -X 'POST' \
  'http://127.0.0.1:8080/api/v1/base/auth' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/x-json-stream' \
  -d '{
  "AppId": "2023012801",
  "AppSecret": "fa2e25cb060c8d748fd16ac5210581f41"
}'

接口返回

{
  "token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJBcHBJZCI6IjIwMjMwMTI4MDEiLCJleHAiOjE2NzQ5MjQ3MTcsImlkZW50aXR5IjoiMjAyMzAxMjgwMSIsIm9yaWdfaWF0IjoxNjc0OTE3NTE3fQ.tL0dbrBMOwHJLAvpdHc88OGGxqUiSQHDR_fAupZ4PKsIrDV3CmYgoM4PPrE-3UW2qjV0cE_f_zQ25aRW8-4SNATAoUU1FGd500Ts-SP5WqK30SqEzih0nhhfGS8nRvDoJVzyD7xKip08EwfrmCyVgajYEi1DNC0y02g7jZ47qlManu53xArIFMAzu7bxQxYZPq5DcF0QF8LQipfKNx_LiFdv5ddv_3qf2J3o9uWWGgR_VjZ5p5u4qFFxGla4mSEUX-t9ZtD335D0YJPUayilGCOw7HyyxbdxVRIq1V6R-S17rJFaB48n8pCvpDY_nfs3tbggAMcoJpdBPwvRZlYwKg",
  "expires": "2023-01-29T00:51:57.1720961+08:00"
}
  • 2.使用token请求API,如下也是rql的使用示例
curl -X 'POST' \
  'http://127.0.0.1:8080/api/v1/apilog/list' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJBcHBJZCI6IjIwMjMwMTI4MDEiLCJleHAiOjE2NzQ5MjQ3MTcsImlkZW50aXR5IjoiMjAyMzAxMjgwMSIsIm9yaWdfaWF0IjoxNjc0OTE3NTE3fQ.tL0dbrBMOwHJLAvpdHc88OGGxqUiSQHDR_fAupZ4PKsIrDV3CmYgoM4PPrE-3UW2qjV0cE_f_zQ25aRW8-4SNATAoUU1FGd500Ts-SP5WqK30SqEzih0nhhfGS8nRvDoJVzyD7xKip08EwfrmCyVgajYEi1DNC0y02g7jZ47qlManu53xArIFMAzu7bxQxYZPq5DcF0QF8LQipfKNx_LiFdv5ddv_3qf2J3o9uWWGgR_VjZ5p5u4qFFxGla4mSEUX-t9ZtD335D0YJPUayilGCOw7HyyxbdxVRIq1V6R-S17rJFaB48n8pCvpDY_nfs3tbggAMcoJpdBPwvRZlYwKg' \
  -H 'Content-Type: application/x-json-stream' \
  -d '{
  "filter": {
    "RequestId": "84692443-987c-4df1-b91c-606fcff6b556"
  },
  "limit": 10,
  "offset": 0,
  "sort": [
    "-StartTime"
  ]
}'

接口返回

{
  "request_id": "cd7548de-9622-46be-8543-478e70ceb793",
  "success": true,
  "data": {
      {
        "ID": 33,
        "CreatedAt": "2023-01-28T22:51:57+08:00",
        "UpdatedAt": "2023-01-28T22:51:57+08:00",
        "DeletedAt": null,
        "RequestId": "84692443-987c-4df1-b91c-606fcff6b556",
        "RequestMethod": "POST",
        "RequestURI": "/api/v1/base/auth",
        "RequestBody": "{\n  \"AppId\": \"2023012801\",\n  \"AppSecret\": \"fa2e25cb060c8d748fd16ac5210581f41\"\n}",
        "StatusCode": 200,
        "RespBody": "{\"token\":\"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJBcHBJZCI6IjIwMjMwMTI4MDEiLCJleHAiOjE2NzQ5MjQ3MTcsImlkZW50aXR5IjoiMjAyMzAxMjgwMSIsIm9yaWdfaWF0IjoxNjc0OTE3NTE3fQ.tL0dbrBMOwHJLAvpdHc88OGGxqUiSQHDR_fAupZ4PKsIrDV3CmYgoM4PPrE-3UW2qjV0cE_f_zQ25aRW8-4SNATAoUU1FGd500Ts-SP5WqK30SqEzih0nhhfGS8nRvDoJVzyD7xKip08EwfrmCyVgajYEi1DNC0y02g7jZ47qlManu53xArIFMAzu7bxQxYZPq5DcF0QF8LQipfKNx_LiFdv5ddv_3qf2J3o9uWWGgR_VjZ5p5u4qFFxGla4mSEUX-t9ZtD335D0YJPUayilGCOw7HyyxbdxVRIq1V6R-S17rJFaB48n8pCvpDY_nfs3tbggAMcoJpdBPwvRZlYwKg\",\"expires\":\"2023-01-29T00:51:57.1720961+08:00\"}",
        "ClientIP": "127.0.0.1",
        "StartTime": "2023-01-28T22:51:57+08:00",
        "ExecTime": "4.6134ms"
      }
  },
  "total": 1, 
  "msg": "操作成功"
}

项目结构概览

├── api
│   └── v1 # v1版本接口目录, 如果有新版本可以继续添加v2/v3
├── cronjob # cron定时任务
├── conf # 配置文件目录(包含测试/预发布/生产环境配置参数及casbin模型配置)
├── initialize # 数据初始化目录
├── internal  # 内部方法
├── logs # 日志文件默认目录(运行代码时生成)
├── middleware # 中间件目录
├── models # 存储层模型定义目录
├── pkg # 公共模块目录
│   ├── global # 全局变量目录 
├── router # 路由目录 
├── vendor # 第三方依赖库 

MySQL数据库准备

#启动mysql linux
docker run -d --name mysql -h mysql   --network=host --restart=always  -v /data/mysql:/var/lib/mysql -v /etc/localtime:/etc/localtime -v /etc/resolv.conf:/etc/resolv.conf -e MYSQL_ROOT_PASSWORD=mysql   --restart always   registry.cn-shenzhen.aliyuncs.com/dev-ops/mysql:8.4.2 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
#启动mysql windows
docker run -d --name mysql -h mysql -p 3306:3306 --restart=always -v D:\MySQL:/var/lib/mysql   -e MYSQL_ROOT_PASSWORD=mysql  --restart always   registry.cn-shenzhen.aliyuncs.com/dev-ops/mysql:8.4.2 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci 

快速开始开发

# 设置常用环境变量
go env -w GOROOT=C:\Go 
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=off 
# 运行
go run main.go

# 热编译运行 gowatch
go install github.com/silenceper/gowatch@latest
gowatch

Prometheus exportor集成

访问地址:http://127.0.0.1:8080/metrics

Swagger文档自动生成

go install github.com/swaggo/swag/cmd/swag@latest 
swag init --parseDependency --parseVendor --parseInternal --parseDepth 1
访问地址:http://127.0.0.1:8080/swagger/index.html

pprof

go tool pprof http://localhost:8080/debug/pprof/heap
go tool pprof http://localhost:8080/debug/pprof/profile
go tool pprof http://localhost:8080/debug/pprof/block
wget http://localhost:8080/debug/pprof/trace?seconds=5

更新依赖包

go install github.com/oligot/go-mod-upgrade@latest
go-mod-upgrade
或
go get -u && go mod tidy

编译

##编译时环境变量
#git分支
GitBranch=$(git name-rev --name-only HEAD)
GitRevision=$(git rev-parse --short HEAD) 
#git commit
GitCommitLog=`git log --pretty=oneline -n 1` 
GitCommitLog=${GitCommitLog//\'/\"}
#构建时间
BuildTime=`date +'%Y.%m.%d.%H%M%S'`
#构建go版本
BuildGoVersion=`go version`
LDFlags="-w -X 'main.GitBranch=${GitBranch}' -X 'main.GitRevision=${GitRevision}' -X 'main.GitCommitLog=${GitCommitLog}' -X 'main.BuildTime=${BuildTime}' -X 'main.BuildGoVersion=${BuildGoVersion}'"
go build -ldflags="$LDFlags" -o  ./go-gin-rest-api

镜像构建-Docker构建

# 使用multi-stage(多阶段构建)需要docker 17.05+版本支持
DOCKER_BUILDKIT=1 docker build  --network=host --no-cache --force-rm -t registry.cn-shenzhen.aliyuncs.com/dev-ops/go-gin-rest-api:1.0.0 .
docker push  registry.cn-shenzhen.aliyuncs.com/dev-ops/go-gin-rest-api:1.0.0
docker save -o go-gin-rest-api-1.0.0.tar  registry.cn-shenzhen.aliyuncs.com/dev-ops/go-gin-rest-api:1.0.0
docker load -i go-gin-rest-api-1.0.0.tar

镜像构建-Buildkit构建

# 使用K8S job方式
kubectl apply -f ./wiki/buildkit-build-job.yaml
# 使用Argo Workflow方式
kubectl apply -f ./wiki/buildkit-argo-workflow-template.yaml

容器运行-Docker运行

docker run -d --name go-gin-rest-api -e RunMode=se --network=host -v /etc/localtime:/etc/localtime --restart always registry.cn-shenzhen.aliyuncs.com/dev-ops/go-gin-rest-api:1.0.0
docker run -d --name go-gin-rest-api -e RunMode=prd -e MYSQL_HOST=xx.xx.xx.xx -e MYSQL_PORT=3306 -e MYSQL_USERNAME=root -e MYSQL_PASSWORD=xxxxxxx -e MYSQL_DATABASE=go-gin-rest-api -p 8080:8080 -v /etc/localtime:/etc/localtime --restart always registry.cn-shenzhen.aliyuncs.com/dev-ops/go-gin-rest-api:1.0.0

容器运行-K8S Deployment运行

kubectl apply -f .\k8s-deploy.yaml