Skip to content

Obytecraft/trinity

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

trinity

Build Status GitHub Actions codecov Go Report Card GoDoc Release

golang restframework plugin with gin+gorm, 5 lines to generate rest api with high security
p.s: django restframework like :)

特性

  • 集成gorm
  • 集成gin
  • 快速注册路由
  • 链路追踪,返回错误代码行数,及sql
  • 快速migrate表并生成权限
  • 支持快速开发rest风格api并实现增删改查,开箱即用
  • JWT token生成,认证,刷新中间件
  • json log风格中间件
  • 支持请求事务
  • 支持自定义用户权限查询
  • 支持自定义接口访问权限
  • 支持自定义接口数据访问权限
  • 自定义分页
  • 自定义过滤查询
  • 自定义搜索
  • 自定义预加载(gorm preload)
  • 自定义排序
  • 自定义查询包含字段
  • 自定义http方法重写
  • 添加了change log

安装

打开终端输入

$ go get -u github.com/PolarPanda611/trinity

done.

文档

// ViewSetCfg for viewset config
type ViewSetCfg struct {
	sync.RWMutex
	// global config
	Db *gorm.DB
	// HasAuthCtl
	// if do the auth check ,default false
	HasAuthCtl bool
	// AuthenticationBackendMap
	// if HasAuthCtl == false ; pass... customize the authentication check , default jwt  ;
	// please set UserID in context
	// e.g : c.Set("UserID", tokenClaims.UID)
	AuthenticationBackendMap map[string]func(c *gin.Context) error
	// GetCurrentUserAuth
	// must be type : func(c *gin.Context, db *gorm.DB) error
	// if HasAuthCtl == false ; pass...
	// get user auth func with UserID if you set in AuthenticationBackend
	// please set UserPermission and UserKey in context
	// e.g : c.Set("UserKey",UserKey) with c.GetString("UserID")
	// e.g : c.Set("UserPermission", UserPermission) with c.GetString("UserID")
	GetCurrentUserAuth interface{}
	// AccessBackendReqMap
	// if HasAuthCtl == false ; pass... customize the access require permission
	AccessBackendRequireMap map[string][]string
	// AccessBackendCheckMap
	// if HasAuthCtl == false ; pass... customize the access check , check user permission
	// e.g : userPermission :=  c.GetString("UserPermission")
	// e.g : requiredPermission := []string{"123"} get with AccessBackendReqMap by default
	// e.g : trinity.CheckAccessAuthorization(requiredPermission , userPermission) , true?allow:deny
	AccessBackendCheckMap map[string]func(v *ViewSetRunTime) error
	// PreloadListMap gorm preload list
	PreloadListMap map[string]map[string]func(db *gorm.DB) *gorm.DB
	// FilterBackendMap : all the query will with this filter backend
	FilterBackendMap map[string]func(c *gin.Context, db *gorm.DB) *gorm.DB
	// FilterByList : only in FilterByList will do the filter
	FilterByList []string
	// FilterCustomizeFunc : can do the customize filter ,mapping with FilterByList
	FilterCustomizeFunc map[string]func(db *gorm.DB, queryValue string) *gorm.DB
	// SearchingByList : with keyword "SearchBy" on url query ,
	// will do the where (xxx =? or xxx=?)
	SearchingByList []string
	// OrderingByList : with keyword "OrderBy" on url query ,
	// only define in OrderingByList will do the order by
	// e.g: OrderBy=xxx-   ==> order by xxx desc
	// e.g: OrderBy=xxx   ==> order by xxx asc
	OrderingByList map[string]bool
	// PageSize default 10
	// keyword : PageNum , PageSize to do the limit and offset
	PageSize int
	// Retrieve: customize retrieve func
	Retrieve func(r *ViewSetRunTime) *ViewSetRunTime
	// Get: customize Get func
	Get func(r *ViewSetRunTime) *ViewSetRunTime
	// Post: customize Post func
	Post func(r *ViewSetRunTime) *ViewSetRunTime
	// Put: customize Put func
	Put func(r *ViewSetRunTime) *ViewSetRunTime
	// Patch: customize Patch func
	Patch func(r *ViewSetRunTime) *ViewSetRunTime
	// Delete: customize Delete func
	Delete func(r *ViewSetRunTime) *ViewSetRunTime
}

例子

  • 准备条件,建立model
//Country model Country
type Country struct {
	Model
	Code        string `json:"code" gorm:"type:varchar(50);index;unique;not null;"`
	Name        string `json:"name" gorm:"type:varchar(50);"`
	Description string `json:"description" gorm:"type:varchar(100);index;"`
}

*初始化trinity设置

// GlobalViewSet global view set config by default value
var GlobalViewSet *trinity.ViewSetCfg


//Inittrinity get default setting
func Inittrinity() {
	trinity.Jwtexpirehour = setting.Cfg.Jwt.Jwtexpirehour
	// Jwtheaderprefix for jwt
	trinity.Jwtheaderprefix = setting.Cfg.Jwt.Jwtheaderprefix
	// Secretkey for jwt
	trinity.Secretkey = setting.Cfg.Secretkey
	// Jwtissuer for jwt
	trinity.Jwtissuer = setting.Cfg.Jwt.Jwtissuer

	GlobalViewSet = trinity.InitDefault(db.Dsource)

	// 在此覆盖默认全局设置
	GlobalViewSet.PageSize = setting.Cfg.Pagesize
}
  • 使用log,jwt中间件及注册路由
func Router() *gin.Engine {
    r := gin.New()
    ````
    r.Use(trinity.JWT())                 // jwt中间件
    r.Use(trinity.LoggerWithFormatter()) // log中间件,链路追踪需开启log中间件,获取TraceID *gin.Context.GetString("TraceID")
    v1 := r.Group("/api/v1")
    {
        // register RESTFUL API router by resouce name
	/*
	*@param RouterGroup :  the router group you want to register
	*@param Resource : the resource of the REST API
	*@param ViewSet : the service of the REST API
	*@param SupportedMethod : the service list of the REST API
	 */
	 // same as 
	 //r.GET("/"+resource+"/:key", viewset)
	 //r.GET("/"+resource, viewset)
	 //r.POST("/"+resource, viewset)
	 //r.PATCH("/"+resource+"/:key", viewset)
	 //r.PUT("/"+resource+"/:key", viewset)
	 //r.DELETE("/"+resource+"/:key", viewset)
        trinity.RegisterRestStyleRouter(v1, "users", servicev1.UserViewSet, []string{"Retrieve", "List", "Create", "Update", "Delete"})
    }
    ```
  • 注册路由处理
// CountryViewSet hanlde router
func CountryViewSet(c *gin.Context) {
	v := trinityinit.GlobalViewSet.New()
	// 在此覆盖默认局部设置
	v.HasAuthCtl = true
	v.FilterByList = []string{"trace_id"}
	// v.GetCurrentUserAuth = func(c *gin.Context, db *gorm.DB) error {
	// 	c.Set("UserPermission", []string{"system.view.Country"})
	// 	return nil
	// }
	utils.HandleResponse(v.NewRunTime(
		c,
		&model.Country{},
		&model.Country{},
		&[]model.Country{},
	).ViewSetServe())
}
  • 支持快速生成过滤

    • 过滤 (系统预置关键字) -关键字列表[]string{"like", "ilike", "in", "notin", "start", "end", "lt", "lte", "gt", "gte", "isnull", "isempty"} -支持关联关系过滤,以双下划线"__"分隔
	// Example :table user(id , name , dpp_id) table dpp {id , code , country_id}, table country {id , name ,create_time}
	// GET : http://127.0.0.1/countries?name__ilike=PolarPanda611&dpp__country_name__ilike=China&dpp__country__create_time__start=2019-01-01
	// ----FilterByList   filter condition must configured in FilterByList config  
	// SETTING : v.FilterByList=[]string{"name__ilike","dpp__country_name__ilike","dpp__country__create_time__start"}
	// EXECUTE:
	// name__ilike ==> name ilike '%PolarPanda611%'  
	// dpp__country__name__ilike => dpp_id in (select id from dpp where country_id in (select id from country where name ilike '%China%' ))
	// dpp__country__create_time__start => dpp_id in (select id from dpp where country_id in (select id from country where create_time > '2019-01-01 00:00:00' ))

	xxx__like=ooo 		=> xxx like '%ooo%'  
	xxx__ilike=ooo 		=> xxx like '%ooo%'  caps no sensitive
	xxx__in=aaa,bbb,ccc => xxx in ['aaa','bbb','ccc']  
	xxx__start=date1	=> xxx > 'date1 00:00:00'  
	xxx__end=date2		=> xxx < 'date2 23:59:59'  
	xxx__isnull=true 	=> xxx is null 
	xxx__isnull=false 	=> xxx is not null 
	xxx__isempty=true	=> (COALESCE("xxx"::varchar ,'') ='' )  
	xxx__isempty=false	=> (COALESCE("xxx"::varchar ,'') !='' )  
	xxx=ooo				=> xxx = ooo
  • 自定义过滤 (自定义关键字和查询方法)
	#Example  :http://127.0.0.1/countries?CustomizeFilterUser=PolarPanda611
	----FilterByList   filter condition must configured in FilterByList config  
	// v.FilterByList=[]string{"CustomizeFilterUser"}
	// v.FilterCustomizeFunc=map[string]func(db *gorm.DB, queryValue string) *gorm.DB{
	//		"CustomizeFilterUser":func(db *gorm.DB, queryValue string) *gorm.DB{
	//			db.Where("name = ?" , "PolarPanda611")
	//		}
	// }

	CustomizeFilterUser=PolarPanda611	=> name = 'PolarPanda611'  
	
  • 自定义搜索 (自定义关键字集合)
	#Example  :http://127.0.0.1/countries?SearchBy=xxx
	----SearchingByList   search condition must configured in in SearchingByList config  
	//v.SearchingByList=[]string{"name","address"}
	SearchBy=xxx		=>(name ilike '%xxx%' or address ilike '%xxx%')  
  • 自定义排序 (自定义排序关键字)
	#Example  :http://127.0.0.1/countries?OrderingBy=-id,name
	----OrderingByList  order by condition must configured in in OrderingByList config  
	OrderingBy=-id,name	=> order by id desc , name    
  • 自定义预加载 (自定义预加载)
	
// QuotationViewSet hanlde router
	func QuotationViewSet(c *gin.Context) {
		v := trinity.NewViewSet()
		v.HasAuthCtl = true
		v.PreloadListMap = map[string]map[string]func(db *gorm.DB) *gorm.DB{
			"RETRIEVE": map[string]func(db *gorm.DB) *gorm.DB{
				"Details":               nil,
				// "Details": func(db *gorm.DB) *gorm.DB {
				// 	return db.Where("id=1 ")
				// },
			},
			"GET": nil,
		}
		v.EnableChangeLog = true
		v.PostValidation = &QuotationPostValidation{}
		v.NewRunTime(
			c,
			&model.Quotation{},
			&model.Quotation{},
			&[]model.Quotation{},
		).ViewSetServe()
	}
  • 自定义分页 (自定义分页数量和页码)
	//默认开启分页
	#Example  :http://127.0.0.1/countries?PageSize=44&PageNum=2
	----queryByPagination By default , the list will be paged , default page size is configured in Pagination config  
	//offset := PageNumFieldInt * PageSizeFieldInt -1 
	//limit := PageSizeFieldInt  
	PageNum=1		=>PageNum= (1,2.....)  
	PageSize=10		=>PageSize= default value:10
	PaginationOn		=>by default :true , will open the pagination , if else , close the pagination, return all the list 
	//关闭分页
	#Example  :http://127.0.0.1/countries?PaginationOn=false
  • 自定义请求回复

// ResponseData http response
type ResponseData struct {
	Status  int         // the http response status  to return
	Result  interface{} // the response data  if req success
	TraceID string
}

// Response handle trinity return value
func Response(r *ViewSetRunTime) {
	var res ResponseData
	res.Status = r.Status
	res.TraceID = r.Gcontext.GetString("TraceID")
	if r.RealError != nil {
		r.Cfg.Logger.LogWriter(r)
		r.Gcontext.Error(r.RealError)
		r.Gcontext.Error(r.UserError)
		res.Result = r.UserError.Error()
		r.Gcontext.AbortWithStatusJSON(r.Status, res)
	} else {
		res.Result = r.ResBody
		r.Gcontext.JSON(r.Status, res)
	}
	return

}
  • 支持请求事务 整个request将会被同一个事物包裹, -如果返回err,则会request整体roll back -如果不返回err,则会request整体commit
	local:
		webapp:
			...
			atomicrequest: true
  • 添加change log 目前不支持嵌套map添加change log
	migrate  		&trinity.AppChangelog{}, 

	在viewset中
	// PartsViewSet hanlde router
	func PartsViewSet(c *gin.Context) {

		v := trinity.NewViewSet()
		v.HasAuthCtl = true
		v.EnableChangeLog = true
		v.NewRunTime(
			c,
			&model.Part{},
			&model.Part{},
			&[]model.Part{},
		).ViewSetServe()
	}

to do list :

支持字段级验证请求数据
外键字段过滤

post and patch not support assosiation update and create

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%