background

Gin and Echo are common microframeworks used in Golang development, but they only support function registration, not structure registration, for example:

import (
    "gopkg.in/gin-gonic/gin.v1"
    "net/http"
)

func main(a){
    router := gin.Default()
    router.GET("/".func(c *gin.Context) {
        c.String(http.StatusOK, "Hello World")
    })
    router.Run(": 8000")}Copy the code

Here we have one route for one handler, but sometimes we want one route for one instance of a structure, executing methods in a structure with different requests. How do we do that? Let’s take Echo as an example for transformation (same with GIN).

define

The transformation should try not to destroy the structure of the existing framework and try to reuse the methods of the existing framework.

To achieve the desired effect, we need to define the following:

  1. The Handler interface, which the registered structure should implement, uses the Handle method to determine which structure method the request should execute
type Handler interface {
	Handle(Context) error
}

HandlerFunc func(Context) error/ / this isEchosomefunc (h HandlerFunc) Handle(ctx Context) error {
	 return h(ctx)
}
Copy the code
  1. The interface corresponding to the request method is used during registration
type GetHandle interface {
	Get(ctx Context) error
}

type PostHandle interface {
	Post(ctx Context) error
}

.....// Other methods

Copy the code
  1. A component used to store structure registration information
typeComponent struct {funcs map[string]map[string]interface{} Component struct {funcs map[string]interface{}Copy the code

This Component should be placed in the Echo structure. When the Echo structure is initialized, the Component should be initialized for use. Component implements the Handler interface above so that each registered structure does not need to implement it itself

The specific implementation

First we write out the structure we need to register


package main

import (
	"fmt"
	"github.com/sereiner/higo"
	"github.com/sereiner/higo/middleware"
	"github.com/sereiner/log"
)

func main() {
	e := higo.New()
	e.Use(middleware.Logger())
	e.Use(middleware.Limit())
	e.Micro("/", NewTA) // You need to implement this by yourself.Fatal(e.start (": 1323"))
}

func NewTA() *TA {
	return &TA{b:12}
}

typeFunc (t *TA) Get(CTX Context) error {fmt.println (struct {b int})"get got it!",t.b)
	returnFunc (t *TA) Post(CTX Context) error {fmt.println (t *TA)"post got it!",t.b)
	return nil
}

Copy the code

Add two new methods to Echo

Func (e *Echo) Micro(Path string, newHandle Interface {}, middleware... {MiddlewareFunc) []*Route {MiddlewareFunc () {MiddlewareFunc () {MiddlewareFunc () {MiddlewareFunc () {MiddlewareFunc () {MiddlewareFunc () {MiddlewareFunc () {MiddlewareFunc ()returne.Any(path,e.GetHandlerFunc(path,newHandle),middleware...) } // GetHandlerFunc gets the information in the structure and transforms it func (e *Echo) GetHandlerFunc(path string,h interface{}) HandlerFunc {tV := reflect.ValueOf(h) hn := tV.Call(nil)[0].Interface() switch handler:= hn.(type) {
	caseGetHandle: var f HandlerFunc = handler.Get // Store the specific method in Component e.component. AddHandler(path, Get,f)} switch handler:= hn.(type) {
	casePostHandle: var f HandlerFunc = handler.post e.Component.AddHandler(path, Post,f)} // Other request types.... // Construct a HandlerFuncreturn func(ctx Context) error {
		return e.Component.Handle(ctx)
	}
}

Copy the code

Finally, there is the Component implementation, directly to the code

type Component struct {
	funcs map[string]map[string]interface{} 
}

func NewComponent() *Component {
	return&Component{funcs:make(map[string]map[string]interface{})}} // Handle func (C *Component) Handle(CTX Context) error { h := c.GetHandler(ctx.Request().URL.Path,ctx.Request().Method)if h == nil {
		ctx.Response().Status = 404
		return nil
	}
	return h(ctx)
}

func (c *Component) AddHandler(path string,method string,h interface{}) {
	_ , ok := c.funcs[path]
	if! ok { s := make(map[string]interface{}) c.funcs[path] = s } _,ok = c.funcs[path][method]if ok {
		fmt.Println("Already registered.")
		return
	}

	c.funcs[path][method] = h
}

func (c *Component) GetHandler(path string,method string) HandlerFunc {

	sc ,ok :=c.funcs[path]
	if! ok {return nil
	}

	h,ok := sc[method]
	if ok {
		return h.(HandlerFunc)
	}
	return nil
}

Copy the code

This is just the reference code, the specific code needs to be further developed

The last

Complete code reference