Giter VIP home page Giter VIP logo

xinliangnote / go-gin-api Goto Github PK

View Code? Open in Web Editor NEW
5.4K 70.0 1.0K 4.22 MB

基于 Gin 进行模块化设计的 API 框架,封装了常用功能,使用简单,致力于进行快速的业务研发。比如,支持 cors 跨域、jwt 签名验证、zap 日志收集、panic 异常捕获、trace 链路追踪、prometheus 监控指标、swagger 文档生成、viper 配置文件解析、gorm 数据库组件、gormgen 代码生成工具、graphql 查询语言、errno 统一定义错误码、gRPC 的使用、cron 定时任务 等等。

Home Page: https://www.yuque.com/xinliangnote/go-gin-api/ngc3x5

License: MIT License

Go 59.77% Shell 0.15% HTML 29.83% JavaScript 9.98% Dockerfile 0.11% Batchfile 0.16%
golang go api-gin gin gin-api jaeger pprof gorm trace graphql

go-gin-api's People

Contributors

anserme avatar xinliangnote avatar zhoumengkang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-gin-api's Issues

运行点击仪表盘报错

image

2021/04/23 14:55:45 d:/code/go-gin-api/internal/api/repository/db_repo/admin_repo/gen_admin.go:98 SLOW SQL >= 200ms
[4670.267ms] [rows:1] SELECT * FROM admin WHERE is_deleted = -1 AND id = 1 AND is_used = 1 LIMIT 1
{"level":"info","time":"2021-04-23 14:55:45","caller":"core/core.go:474","msg":"core-interceptor","domain":"go-gin-api[fat]","method":"GET","path":"/api/admin/info","http_code":200,"business_code":0,"success":true,"cost_seconds":4.6732673,"trace_id":"f62139a047da777a36ac","trace_info":{"trace_id":"f62139a047da777a36ac","request":{"ttl":"un-limit","method":"GET","decoded_url":"/api/admin/info","header":{"Accept":["/"],"Accept-Encoding":["gzip, deflate, br"],"Accept-Language":["zh-CN,zh;q=0.9"],"Authorization":["admin 1EmSu+IbUb6om7UN0SikDMEkuFVJLICgRRvP5alT88E="],"Authorization-Date":["2021-04-23 14:55:41"],"Connection":["keep-alive"],"Content-Type":["application/x-www-form-urlencoded; charset=utf-8"],"Cookie":["login_token=1ba4686338ee7354395ad13f7d3466c1; the_logo_bg=default; the_header_bg=default; the_sidebar_bg=default; nav_url=%2Fdashboard; nav_title=%20%E4%BB%AA%E8%A1%A8%E7%9B%98"],"Referer":["http://127.0.0.1:9999/"],"Sec-Ch-Ua":[""Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99""],"Sec-Ch-Ua-Mobile":["?0"],"Sec-Fetch-Dest":["empty"],"Sec-Fetch-Mode":["cors"],"Sec-Fetch-Site":["same-origin"],"Token":["1ba4686338ee7354395ad13f7d3466c1"],"User-Agent":["Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"],"X-Requested-With":["XMLHttpRequest"]},"body":""},"response":{"header":{"Content-Type":["application/json; charset=utf-8"],"Trace-Id":["f62139a047da777a36ac"],"Vary":["Origin"]},"body":{"username":"admin","nickname":"管理员","mobile":"13888888888"},"http_code":200,"http_code_msg":"OK","cost_seconds":4.6732673},"third_party_requests":null,"debugs":null,"sqls":[{"timestamp":"2021-04-23 14:55:45","stack":"d:/code/go-gin-api/internal/api/repository/db_repo/admin_repo/gen_admin.go:98","sql":"SELECT * FROM admin WHERE is_deleted = -1 AND id = 1 AND is_used = 1 LIMIT 1","rows_affected":1,"cost_seconds":4.6702672}],"redis":[{"timestamp":"2021-04-23 14:55:41","handle":"get","key":"go-gin-api:admin:1ba4686338ee7354395ad13f7d3466c1","cost_seconds":0},{"timestamp":"2021-04-23 14:55:41","handle":"get","key":"go-gin-api:authorized:admin","cost_seconds":0.001}],"grpc":null,"success":true,"cost_seconds":4.6732673}}
{"level":"error","time":"2021-04-23 14:55:46","caller":"core/core.go:359","msg":"got panic","domain":"go-gin-api[fat]","panic":"runtime error: index out of range [0] with length 0","stack":"goroutine 87 [running]:\nruntime/debug.Stack(0x0, 0x0, 0x0)\n\tF:/Go/install/src/runtime/debug/stack.go:24 +0xac\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func2.1(0xc000342360, 0x15170d0, 0xc000388d08, 0xc00168e690, 0xc001640000, 0xc018b9bb4d38149c, 0x178a9cddd, 0x2b80560)\n\td:/code/go-gin-api/internal/pkg/core/core.go:358 +0x7e\npanic(0x138d100, 0xc0019c84e0)\n\tF:/Go/install/src/runtime/panic.go:971 +0x4e6\ngithub.com/xinliangnote/go-gin-api/internal/web/controller/dashboard_handler.(*handler).View.func1(0x15170d0, 0xc0001541d8)\n\td:/code/go-gin-api/internal/web/controller/dashboard_handler/func_view.go:73 +0x107a\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.wrapHandlers.func1(0xc001640000)\n\td:/code/go-gin-api/internal/pkg/core/core.go:214 +0xcb\ngithub.com/gin-gonic/gin.(*Context).Next(0xc001640000)\n\tF:/Go/GOPATH/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 +0x9c\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func3(0xc001640000)\n\td:/code/go-gin-api/internal/pkg/core/core.go:505 +0xec\ngithub.com/gin-gonic/gin.(*Context).Next(0xc001640000)\n\tF:/Go/GOPATH/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 +0x9c\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func2(0xc001640000)\n\td:/code/go-gin-api/internal/pkg/core/core.go:487 +0x285\ngithub.com/gin-gonic/gin.(*Context).Next(0xc001640000)\n\tF:/Go/GOPATH/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 +0x9c\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func1(0xc001640000)\n\td:/code/go-gin-api/internal/pkg/core/core.go:336 +0x6d\ngithub.com/gin-gonic/gin.(*Context).Next(0xc001640000)\n\tF:/Go/GOPATH/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 +0x9c\ngithub.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0xc0003a0140, 0xc001640000)\n\tF:/Go/GOPATH/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:409 +0x46e\ngithub.com/gin-gonic/gin.(*Engine).ServeHTTP(0xc0003a0140, 0x1505ea0, 0xc001638a80, 0xc000193800)\n\tF:/Go/GOPATH/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:367 +0xe5\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.(*mux).ServeHTTP(0xc00008e150, 0x1505ea0, 0xc001638a80, 0xc000193800)\n\td:/code/go-gin-api/internal/pkg/core/core.go:234 +0x5a\nnet/http.serverHandler.ServeHTTP(0xc00024a0e0, 0x1505ea0, 0xc001638a80, 0xc000193800)\n\tF:/Go/install/src/net/http/server.go:2887 +0x22b\nnet/http.(*conn).serve(0xc00034a6e0, 0x1507f10, 0xc0015a8340)\n\tF:/Go/install/src/net/http/server.go:1952 +0x1c25\ncreated by net/http.(*Server).Serve\n\tF:/Go/install/src/net/http/server.go:3013 +0x974\n"}
{"level":"error","time":"2021-04-23 14:55:46","caller":"notify/notify.go:15","msg":"Mail config error","domain":"go-gin-api[fat]"}

优化 gin 参数验证的错误信息

例子

Username string `form:"username" binding:"required"` // 用户名
Nickname string `form:"nickname" binding:"required"` // 昵称

优化前

错误信息为:createRequest.Username' Error:Field validation for 'Username' failed on the 'required' tag\nKey: 'createRequest.Nickname' Error:Field validation for 'Nickname' failed on the 'required' tag"

优化后

如果安装时,选择 简体中文 ,错误信息为:Username为必填字段;Nickname为必填字段;
如果安装时,选择 English,错误信息为:Username is a required field;Nickname is a required field;

docker 部署,重启后,无法登陆 api/login

{"level":"error","time":"2021-05-27 13:23:30","caller":"core/core.go:359","msg":"got panic","domain":"go-gin-api[fat]","panic":"runtime error: invalid memory address or nil pointer dereference","stack":"goroutine 61 [running]:\nruntime/debug.Stack(0xc0015d3060, 0x105bd40, 0x2ac2670)\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x9f\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func2.1(0xc00042a4e0, 0x135d7a0, 0xc0000a8f10, 0xc001596270, 0xc00038a0f0, 0xc023e9148ea4ccca, 0x1148be54cd, 0x2aded00)\n\t/app/internal/pkg/core/core.go:358 +0x19f3\npanic(0x105bd40, 0x2ac2670)\n\t/usr/local/go/src/runtime/panic.go:969 +0x1b9\ngithub.com/xinliangnote/go-gin-api/internal/api/service/authorized_service.(*service).DetailByKey(0xc001598680, 0x135d7a0, 0xc0000a8f08, 0xc00159c280, 0x5, 0x1, 0xc001599940, 0x2)\n\t/app/internal/api/service/authorized_service/service_detailbykey.go:31 +0x132\ngithub.com/xinliangnote/go-gin-api/internal/router/middleware.(*middleware).Signature.func1(0x135d7a0, 0xc0000a8f08)\n\t/app/internal/router/middleware/middle_signature.go:60 +0x724\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.wrapHandlers.func1(0xc00038a0f0)\n\t/app/internal/pkg/core/core.go:214 +0xad\ngithub.com/gin-gonic/gin.(*Context).Next(0xc00038a0f0)\n\t/app/vendor/github.com/gin-gonic/gin/context.go:161 +0x3b\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func3(0xc00038a0f0)\n\t/app/internal/pkg/core/core.go:505 +0x1b0\ngithub.com/gin-gonic/gin.(*Context).Next(0xc00038a0f0)\n\t/app/vendor/github.com/gin-gonic/gin/context.go:161 +0x3b\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func2(0xc00038a0f0)\n\t/app/internal/pkg/core/core.go:487 +0x210\ngithub.com/gin-gonic/gin.(*Context).Next(0xc00038a0f0)\n\t/app/vendor/github.com/gin-gonic/gin/context.go:161 +0x3b\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.New.func1(0xc00038a0f0)\n\t/app/internal/pkg/core/core.go:336 +0x52\ngithub.com/gin-gonic/gin.(*Context).Next(0xc00038a0f0)\n\t/app/vendor/github.com/g
+0x3b\ngithub.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0xc0004383c0, 0xc00038a0f0)\n\t/app/vendor/github.com/gin-gonic/gin/gin.go:409 +0x67a\ngithub.com/gin-gonic/gin.(*Engine).ServeHTTP(0xc0004383c0, 0x1342740, 0xc000444460, 0xc00032f600)\n\t/app/vendor/github.com/gin-gonic/gin/gin.go:367 +0x14d\ngithub.com/xinliangnote/go-gin-api/internal/pkg/core.(*mux).ServeHTTP(0xc0000a8060, 0x1342740, 0xc000444460, 0xc00032f600)\n\t/app/internal/pkg/core/core.go:234 +0x4c\nnet/http.serverHandler.ServeHTTP(0xc0004440e0, 0x1342740, 0xc000444460, 0xc00032f600)\n\t/usr/local/go/src/net/http/server.go:2843 +0xa3\nnet/http.(*conn).serve(0xc000436640, 0x1345bc0, 0xc0003d5c80)\n\t/usr/local/go/src/net/http/server.go:1925 +0x8ad\ncreated by net/http.(*Server).Serve\n\t/usr/local/go/src/net/http/server.go:2969 +0x36c\n"}
{"level":"error","time":"2021-05-27 13:23:30","caller":"notify/notify.go:15","msg":"Mail config error","domain":"go-gin-api[fat]"}

新增脚本 init.sh

新增脚本 init.sh

初始化数据表,在根目录下执行脚本:./scripts/gormgen.sh addr user pass name

  • addr:数据库地址,例如:127.0.0.1:3306
  • user:账号,例如:root
  • pass:密码,例如:123456
  • name:数据库名称,例如:go_gin_api

例如:

./scripts/init.sh 127.0.0.1:3306 root 123456 go_gin_api user_demo

优化脚本 gormgen.sh

优化脚本 gormgen.sh

由原来在配置文件中定义表名改为在命令行下定义,在根目录下执行脚本:./scripts/gormgen.sh addr user pass name tables

  • addr:数据库地址,例如:127.0.0.1:3306
  • user:账号,例如:root
  • pass:密码,例如:123456
  • name:数据库名称,例如:go_gin_api
  • tables:表名,默认为 *,多个表名可用“,”分割,例如:user_demo

例如:

./scripts/gormgen.sh 127.0.0.1:3306 root 123456 go_gin_api user_demo

postgres

后面会支持postgres数据库吗

问题 newContext 使用 sync.Pool 问题

func wrapHandlers(handlers ...HandlerFunc) []gin.HandlerFunc {
	funcs := make([]gin.HandlerFunc, len(handlers))
	for i, handler := range handlers {
		handler := handler
		funcs[i] = func(c *gin.Context) {
			ctx := newContext(c)
			defer releaseContext(ctx)

			handler(ctx)
		}
	}

	return funcs
}

func newContext(ctx *gin.Context) Context {
	context := contextPool.Get().(*context)
	context.ctx = ctx
	return context
}

var contextPool = &sync.Pool{
	New: func() interface{} {
		return new(context)
	},
}

这一段代码中的 newContext(c) 是从 sync.Pool 拿到一个,在 原生的 gin 中,context 本身就是从 sync.Pool 中拿到的

// ServeHTTP conforms to the http.Handler interface.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	c := engine.pool.Get().(*Context)
	c.writermem.reset(w)
	c.Request = req
	c.reset()
	engine.handleHTTPRequest(c)
	engine.pool.Put(c)
}

那么,有个问题,您再一次使用了 sync.Pool 是出于什么考虑呢?我认为您不需要再封装一次 sync.Pool 了

能否加入grpc server支持

现在加入grpc server后,在grpc service里面调用service 里面的方法,需要传入context,但是目前core.Context,但现在context里面都是对*gin.Context的封装,需要传入grpc server context

trace id 的存储问题

您好 我看到trace id是通过c.Set()方法存储的,取的时候是调用c.Value吗?这样会不会有并发读写map的问题呢?

Go Version 不满足要求

我本地golang版本是1.16, 为什么在运行时还是提示Go Version 不满足要求?

检测环境
所需版本: Go Version go1.15+,目前版本:go1.16.3。

日志通道问题

你好,
问下日志先写到通道,如果通道满了阻塞,会影响响应速度吧?

gin自带的参数校验组件不可用

如题, 我在尝试给request的结构体定义校验规则时,发生了校验失效的问题,当我debug时发现默认的校验器没有初始化。

开发代码生成工具,gormgen 和 handlergen

1. gormgen,基于 gorm 生成数据表的 curd 代码

例如:

  • Save
  • Delete
  • QueryOne、QueryAll、Count
  • Limit、Offset
  • Where
  • ...

2. handlergen,根据 type interface 中的方法名,以每个方法生成一个文件。

考虑接口重复提交的问题

1、优化 middlerware 包,新增 Resubmit 路由中间件:

  • 使用方式:在路由文件中这样写 middles.Resubmit() 即可。

2、优化 token 包,新增 UrlSign 签名方式:

  • UrlSign:基于 request body 进行加密生成的签名,此签名不可解密。
  • 基于 UrlSign 加密方式,编写同效果的 PHP 代码。

3、优化 core 包,新增方法:

  • RequestInputParams() url.Values ,获取请求中所有的参数;
  • RequestPostFormParams() url.Values,获取请求中所有的 PostForm 参数;

4、优化 redis 包,新增方法:

  • Exists(keys ...string) bool,判断 keys 是否存在;

新增 web 功能

新增 web 功能

  • 系统管理员
  • 登录/登出
  • 接口增加权限认证

优化脚本 handlergen.sh

优化脚本 handlergen.sh

  • 调整 interface 中方法注释,新增 @Tags@Router
  • 生成的方法中,新增 swagger 注释信息;

例如:

type Handler interface {
	
	// Create 创建用户
	// @Tags User
	// @Router /user/create [post]
	Create() core.HandlerFunc
}

生成的方法注释如下:

// 创建用户
// @Summary 创建用户
// @Description 创建用户
// @Tags User
// @Accept  json
// @Produce  json
// @Param Request body createRequest true "请求信息"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /user/create [post]
func (h *handler) Create() core.HandlerFunc {}

新增 web 功能

新增管理面板

  • 仪表盘
  • 配置信息
  • 代码生成
  • 初始化
    • gormgen
    • handlergen
    • 接口文档
  • GraphQL
  • 接口指标

新增 web 功能

新增 web 功能

  • 授权调用方
    • 使用说明
  • 工具箱
    • 调用日志

缓存清理,数据一致性

更改了用户菜单授权,redis中的缓存没有清理掉,导致权限从页面看不生效——数据不一致
手动清理掉redis的缓存后,未命中的情况下没有再去mysql从新缓存数据

日志显示

开发环境为什么也要把日志都写入文件呢 为什么没有开关

接口定义疑问

type Hash interface {
	i()

	// hashids
	HashidsEncode(params []int) (string, error)
	HashidsDecode(hash string) ([]int, error)
}

为何我看到在您的项目中有大量的类似这样的接口定义,i() 这个方法在实现的时候又是一个空的方法,这样做有什么含义么?

建议支持多种数据库:例如Postgresql和Oracle

以下基于commit:9aa0067e07d036b4ae57168d2bd138d142dff80e
建议使用gorm在程序初始化的时候创建表,eg:

type User struct {
	//通过在字段后面的标签说明,定义golang字段和表字段的关系
	//例如 `gorm:"column:username"` 标签说明含义是: Mysql表的列名(字段名)为username
	//这里golang定义的Username变量和MYSQL表字段username一样,他们的名字可以不一样。
	Id int64 `gorm:"column:username;not null;type:int(4) primary key auto_increment;comment:'用户名'"`
	Password string `gorm:"column:password;type:varchar(30);index:idx_name"`
	//创建时间,时间戳
	CreateTime int64 `gorm:"column:createtime"`
}

同时建议不要在代码中直接写sql
eg:internal/api/controller/tool_handler/func_tables.go:48
切换数据库的时候很痛苦
(postgres要在连接的时候指定数据库,Oracle要在连接的时候指定用户)
谢谢

提 issues 必看

先看下常见问题列表:https://www.yuque.com/xinliangnote/go-gin-api/pmfdon 是否可以帮你解决?
如果不能,请按照下列格式提交 issues ~

如果是代码相关的问题,请进行如下描述:

问题描述

问题出现的环境背景及自己尝试过哪些方法

相关代码

粘贴代码文本(请勿用截图)

你期待的结果是什么?实际看到的错误信息又是什么?

优化 third_party_request

优化 third_party_request

  • third_party_requestrepository 目录移出;
  • 每个方法创建一个 .go 文件,以 DemoGet 为例,创建 demoget.go
    • 方法:DemoGet(name string, opts ...httpclient.Option) (res *demoGetResponse, err error)
    • 设置重试规则:DemoGetRetryVerify(body []byte) (shouldRetry bool)
    • 设置告警规则:DemoGetAlarmVerify(body []byte) (shouldAlarm bool)
    • 设置 Mock 数据:DemoGetMock() (body []byte)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.