# go-gin-rest-api **Repository Path**: xmlgrg/go-gin-rest-api ## Basic Information - **Project Name**: go-gin-rest-api - **Description**: go-gin-rest-api - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2024-05-28 - **Last Updated**: 2024-10-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

go-gin-rest-api

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

Go version Gin version Gorm version

## 配套前端[ice-antd](https://github.com/linclin/ice-antd) - [ice.js](https://github.com/alibaba/ice) 阿里开源飞冰React框架 [文档](https://v3.ice.work/docs/guide/start) - [Ant Design Pro](https://github.com/ant-design/pro-components) 蚂蚁开源Ant Design Pro前端UI组件 [文档](https://procomponents.ant.design/components) ![工作台](wiki/image/index.png) ![角色管理](wiki/image/role.png) ## 主要功能 - 基于`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](https://github.com/gin-gonic/gin) 一款高效的golang web框架 [教程](https://gin-gonic.com/zh-cn/docs/) - [gorm](https://gorm.io/gorm) 数据库ORM管理框架, 可自行扩展多种数据库类型 [教程](https://gorm.io/zh_CN/) - [rql](https://github.com/a8m/rql) 用于REST的资源查询语言,作为http请求和orm之间的连接器,gin和gorm的连接器 - [viper](https://github.com/spf13/viper) 配置管理工具, 支持多种配置文件类型.[教程](https://darjun.github.io/2020/01/18/godailylib/viper/) - [jwt](https://github.com/appleboy/gin-jwt) JWT token中间件 - [casbin](https://github.com/casbin/casbin) 基于角色的访问控制模型(RBAC) [教程](https://darjun.github.io/2020/06/12/godailylib/casbin/) - [validator](https://github.com/go-playground/validator) 请求参数校验, 版本V10. [教程](https://darjun.github.io/2020/04/04/godailylib/validator/) - [lumberjack](https://github.com/natefinch/lumberjack) 日志切割工具, 高效分离大日志文件, 按日期保存文件 - [cast](https://github.com/spf13/cast) 一个小巧、实用的类型转换库,用于将一个类型转为另一个类型 [教程](https://darjun.github.io/2020/01/20/godailylib/cast/) - [go-cache](https://github.com/patrickmn/go-cache) 缓存库 [教程](https://cloud.tencent.com/developer/article/2176204) - [resty](https://github.com/go-resty/resty) Go的简单HTTP和REST请求客户端 [教程](https://darjun.github.io/2021/06/26/godailylib/resty/) - [cron](https://github.com/robfig/cron) 实现了 cron 规范解析器和任务运行器,简单来讲就是包含了定时任务所需的功能 [教程](https://darjun.github.io/2020/06/25/godailylib/cron) - [lo](https://github.com/samber/lo) 基于泛型实现的Golang工具库 感谢[Go 每日一库](https://github.com/darjun/go-daily-lib)提供的详细教程 ## gin中间件 - [appleboy/gin-jwt](https://github.com/appleboy/gin-jwt) 权限认证中间件 -- 处理登录、登出、无状态token校验 - [casbin](https://github.com/casbin/casbin/) 和[casbin/gorm-adapter](https://github.com/casbin/gorm-adapter)权限访问中间件 -- 基于Cabin RBAC, 对不同角色访问不同API进行校验 - [sentinel](https://github.com/sentinel-group/sentinel-go-adapters/gin) sentinel流量控制中间件 -- api流量控制和熔断降级 - [gin-contrib/requestid](https://github.com/gin-contrib/requestid) requestid中间件 -- 接口trace id,每次api请求均会生成唯一id返回客户端,并保存数据库接口日志表 - [gin-contrib/cors](https://github.com/gin-contrib/cors) cors跨域中间件-- 所有请求均可跨域访问 - [gin-contrib/gzip](https://github.com/gin-contrib/gzip) gzip中间件-- 所有API返回均进行压缩 - [gin-contrib/pprof](https://github.com/gin-contrib/pprof) pprof中间件 - [zsais/go-gin-prometheus](https://github.com/zsais/go-gin-prometheus) prometheus中间件 - [swaggo/gin-swagger](https://github.com/swaggo/gin-swagger) swagger中间件 - `Exception` 全局异常处理中间件 -- 使用golang recover特性, 捕获所有异常, 保存到日志, 方便追溯 - `AccessLog` 请求日志中间件 -- 每次请求的路由、IP自动写入日志 ## 接口使用指南 - golang客户端示例代码参见client目录,使用`resty`和`go-cache`编写 - 1.获取JWT生成的token(2小时超时),AppId和AppSecret存放SysSystem模型 ``` shell 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" }' ``` 接口返回 ``` shell { "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的使用示例 ``` shell 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" ] }' ``` 接口返回 ``` shell { "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构建 ``` shell # 使用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构建 ``` shell # 使用K8S job方式 kubectl apply -f ./wiki/buildkit-build-job.yaml # 使用Argo Workflow方式 kubectl apply -f ./wiki/buildkit-argo-workflow-template.yaml ``` ## 容器运行-Docker运行 ``` shell 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运行 ``` shell kubectl apply -f .\k8s-deploy.yaml ```