Skip to content

Instantly share code, notes, and snippets.

@iflamed
Last active October 9, 2023 03:40
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iflamed/8a50f22c961c9cd2e027955d4a2494a0 to your computer and use it in GitHub Desktop.
Save iflamed/8a50f22c961c9cd2e027955d4a2494a0 to your computer and use it in GitHub Desktop.
// Package http
package http
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Context struct {
*gin.Context
}
// Ok implement your context method like below
func (c *Context) Ok(body string) {
c.String(http.StatusOK, body)
}
type Handler interface {
GetHandler(action string) HandlerFunc
Clone() Handler
}
type BasicHandler struct {
Handlers map[string]HandlerFunc
}
func (b *BasicHandler) SetHandler(action string, handlerFunc HandlerFunc) {
if b.Handlers == nil {
b.Handlers = make(map[string]HandlerFunc)
}
b.Handlers[action] = handlerFunc
}
func (b *BasicHandler) GetHandler(action string) HandlerFunc {
return b.Handlers[action]
}
// register route and use custom context
func initRoutes(r *router) {
r.GET("/hello", func(c *Context) {
c.Ok("Hello world")
})
}
type router struct {
*gin.RouterGroup
}
type Controller struct {
r *router
h Handler
}
type HandlerFunc func(c *Context)
func newRouter(e *gin.Engine) *router {
return &router{
RouterGroup: &e.RouterGroup,
}
}
func (r *router) GET(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodGet, relativePath, handlers...)
return r
}
func (r *router) POST(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodPost, relativePath, handlers...)
return r
}
func (r *router) PUT(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodPut, relativePath, handlers...)
return r
}
func (r *router) PATCH(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodPatch, relativePath, handlers...)
return r
}
func (r *router) HEAD(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodHead, relativePath, handlers...)
return r
}
func (r *router) OPTIONS(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodOptions, relativePath, handlers...)
return r
}
func (r *router) DELETE(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodDelete, relativePath, handlers...)
return r
}
func (r *router) CONNECT(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodConnect, relativePath, handlers...)
return r
}
func (r *router) TRACE(relativePath string, handlers ...HandlerFunc) *router {
r.wrapRoute(http.MethodTrace, relativePath, handlers...)
return r
}
func (r *router) Use(handlers ...HandlerFunc) *router {
r.wrapRoute("use", "", handlers...)
return r
}
func (r *router) Group(relativePath string, handlers ...HandlerFunc) *router {
g := r.wrapRoute("group", relativePath, handlers...).(*gin.RouterGroup)
return &router{
RouterGroup: g,
}
}
func (r *router) wrapRoute(method string, relativePath string, handlers ...HandlerFunc) gin.IRoutes {
hds := make([]gin.HandlerFunc, 0, len(handlers))
for _, hd := range handlers {
hds = append(hds, wrapHandler(hd))
}
switch method {
case http.MethodGet:
return r.RouterGroup.GET(relativePath, hds...)
case http.MethodPost:
return r.RouterGroup.POST(relativePath, hds...)
case http.MethodPut:
return r.RouterGroup.PUT(relativePath, hds...)
case http.MethodPatch:
return r.RouterGroup.PATCH(relativePath, hds...)
case http.MethodHead:
return r.RouterGroup.HEAD(relativePath, hds...)
case http.MethodOptions:
return r.RouterGroup.OPTIONS(relativePath, hds...)
case http.MethodDelete:
return r.RouterGroup.DELETE(relativePath, hds...)
case http.MethodConnect:
return r.RouterGroup.Handle(http.MethodConnect, relativePath, hds...)
case "use":
return r.RouterGroup.Use(hds...)
case "group":
return r.RouterGroup.Group(relativePath, hds...)
}
return r.RouterGroup.Handle(http.MethodTrace, relativePath, hds...)
}
func wrapHandler(hd HandlerFunc) gin.HandlerFunc {
return func(ctx *gin.Context) {
hd(&Context{ctx})
}
}
func (r *router) Controller(h Handler) *Controller {
return &Controller{r: r, h: h}
}
func (c *Controller) GET(relativePath, action string) *Controller {
c.r.GET(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) POST(relativePath, action string) *Controller {
c.r.POST(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) PUT(relativePath, action string) *Controller {
c.r.PUT(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) PATCH(relativePath, action string) *Controller {
c.r.PATCH(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) HEAD(relativePath, action string) *Controller {
c.r.HEAD(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) OPTIONS(relativePath, action string) *Controller {
c.r.OPTIONS(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) DELETE(relativePath, action string) *Controller {
c.r.DELETE(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) CONNECT(relativePath, action string) *Controller {
c.r.CONNECT(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) TRACE(relativePath, action string) *Controller {
c.r.TRACE(relativePath, c.cloneHandler(action, c.h))
return c
}
func (c *Controller) Use(action string) *Controller {
c.r.wrapRoute("use", "", c.cloneHandler(action, c.h))
return c
}
func (c *Controller) Group(relativePath, action string) *Controller {
g := c.r.wrapRoute("group", relativePath, c.cloneHandler(action, c.h)).(*gin.RouterGroup)
r := &router{
RouterGroup: g,
}
return r.Controller(c.h)
}
func (c *Controller) Resource(relativePath string) *Controller {
c.GET(relativePath, http.MethodGet)
c.POST(relativePath, http.MethodPost)
c.PUT(relativePath, http.MethodPut)
c.PATCH(relativePath, http.MethodPatch)
c.DELETE(relativePath, http.MethodDelete)
return c
}
func (c *Controller) cloneHandler(action string, h Handler) HandlerFunc {
return func(c *Context) {
hd := h.Clone().GetHandler(action)
if hd != nil {
hd(c)
} else {
c.Error(http.StatusInternalServerError, action+" handler not implemented", gin.H{})
}
}
}
// create gin instance to start server
func createServer() *http.Server {
engine := gin.Default()
initRoutes(newRouter(engine))
return &http.Server{
Addr: "127.0.0.1:8080",
Handler: engine,
}
}
@iflamed
Copy link
Author

iflamed commented Mar 13, 2023

May be the best way to custom gin context. Create a new context based on gin.context and create a new router.

@dbing
Copy link

dbing commented Oct 9, 2023

👍🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment