go web framework gin group api 设计

假如让你来设计group api, 你该怎么设计呢?

group api 和普通api的区别在于前缀不同,如果group api的版本为v1.0 那么相对应的url为/v1.0/xxx, 如果是普通api的话那么api相对应的版本为/xxx

在gin web framework 中设计的原则也是以相对路径来区分。

// RouterGroup is used internally to configure router, a RouterGroup is associated with
// a prefix and an array of handlers (middleware).
type RouterGroup struct {
        Handlers HandlersChain #处理函数
        basePath string  #相对路径
        engine   *Engine #存在哪个engine上
        root     bool  #基于基树判断是否为root
}

先看gin中group 的添加规则:

     router := gin.New()
        users := router.Group("/users")

先看gin.New()默认的basePath是什么。

// New returns a new blank Engine instance without any middleware attached.
// By default the configuration is:
// - RedirectTrailingSlash:  true
// - RedirectFixedPath:      false
// - HandleMethodNotAllowed: false
// - ForwardedByClientIP:    true
// - UseRawPath:             false
// - UnescapePathValues:     true
func New() *Engine {
        debugPrintWARNINGNew()
        engine := &Engine{
                RouterGroup: RouterGroup{
                        Handlers: nil,
                        basePath: "/",  #默认为“/”
                        root:     true,
                },
                FuncMap:                template.FuncMap{},
                RedirectTrailingSlash:  true,
                RedirectFixedPath:      false,
                HandleMethodNotAllowed: false,
                ForwardedByClientIP:    true,
                AppEngine:              defaultAppEngine,
                UseRawPath:             false,
                UnescapePathValues:     true,
                MaxMultipartMemory:     defaultMultipartMemory,
                trees:                  make(methodTrees, 0, 9),
                delims:                 render.Delims{Left: "{{", Right: "}}"},
                secureJsonPrefix:       "while(1);",
        }
        engine.RouterGroup.engine = engine
        engine.pool.New = func() interface{} {
                return engine.allocateContext()
        }
        return engine
}

  

查看router.Group("/users") 的调用

// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
// For example, all the routes that use a common middleware for authorization could be grouped.
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
        return &RouterGroup{
                Handlers: group.combineHandlers(handlers),
                basePath: group.calculateAbsolutePath(relativePath), #根据relativePath这个参数,计算basePath
                engine:   group.engine,
        }
}

 查看group.calculateAbsolutePath(relativePath) 的调用

func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
        return joinPaths(group.basePath, relativePath)
}

 再查看joinPaths的实现

func joinPaths(absolutePath, relativePath string) string {
        if relativePath == "" { #如果没有relativePath 直接返回absolutePath,默认为“/”
                return absolutePath
        }
        #处理最后的“/”
        finalPath := path.Join(absolutePath, relativePath)
        appendSlash := lastChar(relativePath) == '/' && lastChar(finalPath) != '/'
        if appendSlash {
                return finalPath + "/"
        }
        return finalPath
}