add bindoutput & rewrite shapeoutput
This commit is contained in:
		
							parent
							
								
									8489fc1556
								
							
						
					
					
						commit
						f978fa3f87
					
				
							
								
								
									
										40
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								api.go
									
									
									
									
									
								
							@ -1,6 +1,9 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/go-playground/validator/v10"
 | 
			
		||||
	"qoobing.com/gomod/log"
 | 
			
		||||
@ -10,6 +13,7 @@ import (
 | 
			
		||||
var (
 | 
			
		||||
	validate              = validator.New()
 | 
			
		||||
	requestLogidGetter    = defaultLogidGetter
 | 
			
		||||
	handlerMapper         = map[string]Handler{}
 | 
			
		||||
	errCodeUnknownError   = -10000
 | 
			
		||||
	errCodeUnimplementApi = -20401
 | 
			
		||||
)
 | 
			
		||||
@ -40,8 +44,27 @@ func NewEngine() *Engine {
 | 
			
		||||
	return &Engine{e}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Engine) POST(uri string, handler HandlerFunc) {
 | 
			
		||||
	e.Engine.POST(uri, handlerWrapper(handler))
 | 
			
		||||
func (e *Engine) POST(uri string, handler Handler) {
 | 
			
		||||
	h := handlerWrapper(handler.HandlerFunc())
 | 
			
		||||
	handlerMapper[fmt.Sprintf("%v", h)] = handler
 | 
			
		||||
	e.Engine.POST(uri, h)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handlerWrapper
 | 
			
		||||
func handlerWrapper(handler HandlerFunc) gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		if icc, ok := c.Get("cc"); !ok {
 | 
			
		||||
			log.Errorf("Unreachable Code: can not get cc(*api.Context) from *gin.Context")
 | 
			
		||||
		} else if cc, ok := icc.(*Context); !ok {
 | 
			
		||||
			log.Debugf("Unreachable Code: cc from *gin.Context is type of:[%s]", reflect.TypeOf(icc).String())
 | 
			
		||||
			log.Errorf("Unreachable Code: cc from *gin.Context is not type of *api.Context")
 | 
			
		||||
		} else {
 | 
			
		||||
			defer cc.TryRecover()
 | 
			
		||||
			cc.AppId = c.GetString("appid")
 | 
			
		||||
			cc.UserId = c.GetUint64("userid")
 | 
			
		||||
			handler(cc)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// middlewareMyApiEngine myapi engine middleware
 | 
			
		||||
@ -72,6 +95,19 @@ func defaultLogidGetter(c *gin.Context) (logid string) {
 | 
			
		||||
	panic("unreachable code")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DumpHandler(c *Context) error {
 | 
			
		||||
	errmsg := "api not implemented"
 | 
			
		||||
	errcode := errCodeUnimplementApi
 | 
			
		||||
	return c.RESULT_ERROR(errcode, errmsg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ErrorHandler(c *gin.Context, errcode int, errmsg string) {
 | 
			
		||||
	handler := handlerWrapper(func(c *Context) error {
 | 
			
		||||
		return c.RESULT_ERROR(errcode, errmsg)
 | 
			
		||||
	})
 | 
			
		||||
	handler(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func InitErrCodes(errcodes map[string]int) {
 | 
			
		||||
	if code, ok := errcodes["ErrCodeUnknownError"]; ok {
 | 
			
		||||
		errCodeUnknownError = code
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								context.go
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								context.go
									
									
									
									
									
								
							@ -25,6 +25,7 @@ type Context struct {
 | 
			
		||||
	resultentry string
 | 
			
		||||
	httpstatus  int
 | 
			
		||||
	starttime   time.Time
 | 
			
		||||
	output      interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(c *gin.Context) *Context {
 | 
			
		||||
@ -89,6 +90,29 @@ func (c *Context) BindInput(i interface{}) (err error) {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Context) BindOutput(o interface{}) (err error) {
 | 
			
		||||
	var v = reflect.ValueOf(o)
 | 
			
		||||
	if v.Kind() != reflect.Pointer {
 | 
			
		||||
		return fmt.Errorf("output is NOT a pointer")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var e = v.Elem()
 | 
			
		||||
	var t = e.Type()
 | 
			
		||||
	if _, ok := t.FieldByName("ErrCode"); !ok {
 | 
			
		||||
		return fmt.Errorf("out have no field ErrCode")
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := t.FieldByName("ErrMsg"); !ok {
 | 
			
		||||
		return fmt.Errorf("out have no field ErrMsg")
 | 
			
		||||
	}
 | 
			
		||||
	if code := e.FieldByName("ErrCode"); !code.CanSet() {
 | 
			
		||||
		return fmt.Errorf("output.ErrCode can not be set, " +
 | 
			
		||||
			"output is NOT a pointer or output have no field 'ErrCode'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.output = o
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Context) SetCookie(cookie *http.Cookie) {
 | 
			
		||||
	if cookie.Path == "" {
 | 
			
		||||
		cookie.Path = "/"
 | 
			
		||||
@ -130,19 +154,46 @@ func (c *Context) RESULT(output interface{}) error {
 | 
			
		||||
	if _, ok := t.FieldByName("ErrCode"); !ok {
 | 
			
		||||
		errstr := "Result MUST have 'ErrCode' field"
 | 
			
		||||
		output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
 | 
			
		||||
		c.ShapeOutput(output)
 | 
			
		||||
		c.IndentedJSON(c.httpstatus, output)
 | 
			
		||||
		return errors.New(errstr)
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := t.FieldByName("ErrMsg"); !ok {
 | 
			
		||||
		errstr := "Result MUST have 'ErrMsg' field"
 | 
			
		||||
		output = BaseWithErrCodeOutput{errCodeUnknownError, errstr}
 | 
			
		||||
		c.ShapeOutput(output)
 | 
			
		||||
		c.IndentedJSON(c.httpstatus, output)
 | 
			
		||||
		return errors.New(errstr)
 | 
			
		||||
	}
 | 
			
		||||
	c.ShapeOutput(output)
 | 
			
		||||
	c.IndentedJSON(c.httpstatus, output)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Context) ShapeOutput(o interface{}) {
 | 
			
		||||
	if c.output == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var out, ok = o.(BaseWithErrCodeOutput)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var e = reflect.ValueOf(c.output).Elem()
 | 
			
		||||
	e.FieldByName("ErrMsg").SetString(out.ErrMsg)
 | 
			
		||||
	e.FieldByName("ErrCode").SetInt(int64(out.ErrCode))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Context) Handler() Handler {
 | 
			
		||||
	h := c.Context.Handler()
 | 
			
		||||
	if handler, ok := handlerMapper[fmt.Sprintf("%v", h)]; ok {
 | 
			
		||||
		return handler
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Context) RESULT_ERROR(eno int, err string) error {
 | 
			
		||||
	if c.resultentry == "" {
 | 
			
		||||
		c.resultentry = "RESULT_ERROR"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
			
		||||
module qoobing.com/gomod/api
 | 
			
		||||
 | 
			
		||||
go 1.16
 | 
			
		||||
go 1.19
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/gin-gonic/gin v1.8.1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										76
									
								
								routes.go
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								routes.go
									
									
									
									
									
								
							@ -1,49 +1,43 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
// ///////////////////////////////////////////////////////////////////
 | 
			
		||||
// IRouter & IRoutes in gin, we redefine it simple
 | 
			
		||||
// ///////////////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//	// IRouter defines all router handle interface
 | 
			
		||||
//	// includes single and group router.
 | 
			
		||||
//	type IRouter interface {
 | 
			
		||||
//		IRoutes
 | 
			
		||||
//		Group(string, ...HandlerFunc) *RouterGroup
 | 
			
		||||
//	}
 | 
			
		||||
//
 | 
			
		||||
//	// IRoutes defines all router handle interface.
 | 
			
		||||
//	type IRoutes interface {
 | 
			
		||||
//		Use(...HandlerFunc) IRoutes
 | 
			
		||||
//
 | 
			
		||||
//		Handle(string, string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		Any(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		GET(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		POST(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		DELETE(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		PATCH(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		PUT(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		OPTIONS(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//		HEAD(string, ...HandlerFunc) IRoutes
 | 
			
		||||
//
 | 
			
		||||
//		StaticFile(string, string) IRoutes
 | 
			
		||||
//		StaticFileFS(string, string, http.FileSystem) IRoutes
 | 
			
		||||
//		Static(string, string) IRoutes
 | 
			
		||||
//		StaticFS(string, http.FileSystem) IRoutes
 | 
			
		||||
//	}
 | 
			
		||||
//
 | 
			
		||||
// ///////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"qoobing.com/gomod/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type routes struct {
 | 
			
		||||
	gin.IRoutes
 | 
			
		||||
type Handler interface {
 | 
			
		||||
	HandlerFunc() HandlerFunc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type HandlerFunc func(*Context) error
 | 
			
		||||
 | 
			
		||||
type IRoutes interface {
 | 
			
		||||
	POST(uri string, handler HandlerFunc)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r routes) POST(uri string, handler HandlerFunc) {
 | 
			
		||||
	r.IRoutes.POST(uri, handlerWrapper(handler))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DumpHandler(c *Context) error {
 | 
			
		||||
	return c.RESULT_ERROR(errCodeUnimplementApi, "api not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ErrorHandler(c *gin.Context, errcode int, errmsg string) {
 | 
			
		||||
	handler := handlerWrapper(func(c *Context) error {
 | 
			
		||||
		return c.RESULT_ERROR(errcode, errmsg)
 | 
			
		||||
	})
 | 
			
		||||
	handler(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handlerWrapper(handler HandlerFunc) gin.HandlerFunc {
 | 
			
		||||
	return func(c *gin.Context) {
 | 
			
		||||
		if icc, ok := c.Get("cc"); !ok {
 | 
			
		||||
			log.Errorf("Unreachable Code: can not get cc(*api.Context) from *gin.Context")
 | 
			
		||||
		} else if cc, ok := icc.(*Context); !ok {
 | 
			
		||||
			log.Debugf("Unreachable Code: cc from *gin.Context is type of:[%s]", reflect.TypeOf(icc).String())
 | 
			
		||||
			log.Errorf("Unreachable Code: cc from *gin.Context is not type of *api.Context")
 | 
			
		||||
		} else {
 | 
			
		||||
			defer cc.TryRecover()
 | 
			
		||||
			cc.AppId = c.GetString("appid")
 | 
			
		||||
			cc.UserId = c.GetUint64("userid")
 | 
			
		||||
			handler(cc)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	POST(uri string, handler Handler)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user