go.sdls.io/sin@v0.0.9/pkg/sin/routergroup.go (about) 1 // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 2 // Use of this source code is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 package sin 6 7 import ( 8 "net/http" 9 "regexp" 10 ) 11 12 // reg match english letters for http method name 13 var regEnLetter = regexp.MustCompile("^[A-Z]+$") 14 15 // IRouter defines all router handle interface includes single and group router. 16 type IRouter interface { 17 IRoutes 18 Group(string, ...HandlerFunc) *RouterGroup 19 } 20 21 // IRoutes defines all router handle interface. 22 type IRoutes interface { 23 Use(...HandlerFunc) IRoutes 24 25 Handle(string, string, ...HandlerFunc) IRoutes 26 Any(string, ...HandlerFunc) IRoutes 27 GET(string, ...HandlerFunc) IRoutes 28 POST(string, ...HandlerFunc) IRoutes 29 DELETE(string, ...HandlerFunc) IRoutes 30 PATCH(string, ...HandlerFunc) IRoutes 31 PUT(string, ...HandlerFunc) IRoutes 32 OPTIONS(string, ...HandlerFunc) IRoutes 33 HEAD(string, ...HandlerFunc) IRoutes 34 } 35 36 // RouterGroup is used internally to configure router, a RouterGroup is associated with 37 // a prefix and an array of handlers (middleware). 38 type RouterGroup struct { 39 engine *Engine 40 basePath string 41 Handlers HandlersChain 42 root bool 43 } 44 45 var _ IRouter = &RouterGroup{} 46 47 // Use adds middleware to the group, see example code in GitHub. 48 func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes { 49 group.Handlers = append(group.Handlers, middleware...) 50 return group.returnObj() 51 } 52 53 // Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix. 54 // For example, all the routes that use a common middleware for authorization could be grouped. 55 func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { 56 return &RouterGroup{ 57 Handlers: group.combineHandlers(handlers), 58 basePath: group.calculateAbsolutePath(relativePath), 59 engine: group.engine, 60 } 61 } 62 63 // BasePath returns the base path of router group. 64 // For example, if v := router.Group("/rest/n/v1/api"), v.BasePath() is "/rest/n/v1/api". 65 func (group *RouterGroup) BasePath() string { 66 return group.basePath 67 } 68 69 func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes { 70 absolutePath := group.calculateAbsolutePath(relativePath) 71 handlers = group.combineHandlers(handlers) 72 group.engine.addRoute(httpMethod, absolutePath, handlers) 73 return group.returnObj() 74 } 75 76 // Handle registers a new request handle and middleware with the given path and method. 77 // The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes. 78 // See the example code in GitHub. 79 // 80 // For GET, POST, PUT, PATCH and DELETE requests the respective shortcut 81 // functions can be used. 82 // 83 // This function is intended for bulk loading and to allow the usage of less 84 // frequently used, non-standardized or custom methods (e.g. for internal 85 // communication with a proxy). 86 func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes { 87 if matched := regEnLetter.MatchString(httpMethod); !matched { 88 panic("http method " + httpMethod + " is not valid") 89 } 90 return group.handle(httpMethod, relativePath, handlers) 91 } 92 93 // POST is a shortcut for router.Handle("POST", path, handle). 94 func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes { 95 return group.handle(http.MethodPost, relativePath, handlers) 96 } 97 98 // GET is a shortcut for router.Handle("GET", path, handle). 99 func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { 100 return group.handle(http.MethodGet, relativePath, handlers) 101 } 102 103 // DELETE is a shortcut for router.Handle("DELETE", path, handle). 104 func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes { 105 return group.handle(http.MethodDelete, relativePath, handlers) 106 } 107 108 // PATCH is a shortcut for router.Handle("PATCH", path, handle). 109 func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes { 110 return group.handle(http.MethodPatch, relativePath, handlers) 111 } 112 113 // PUT is a shortcut for router.Handle("PUT", path, handle). 114 func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes { 115 return group.handle(http.MethodPut, relativePath, handlers) 116 } 117 118 // OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle). 119 func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes { 120 return group.handle(http.MethodOptions, relativePath, handlers) 121 } 122 123 // HEAD is a shortcut for router.Handle("HEAD", path, handle). 124 func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes { 125 return group.handle(http.MethodHead, relativePath, handlers) 126 } 127 128 // Any registers a route that matches all the HTTP methods. 129 // GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE. 130 func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes { 131 group.handle(http.MethodGet, relativePath, handlers) 132 group.handle(http.MethodPost, relativePath, handlers) 133 group.handle(http.MethodPut, relativePath, handlers) 134 group.handle(http.MethodPatch, relativePath, handlers) 135 group.handle(http.MethodHead, relativePath, handlers) 136 group.handle(http.MethodOptions, relativePath, handlers) 137 group.handle(http.MethodDelete, relativePath, handlers) 138 group.handle(http.MethodConnect, relativePath, handlers) 139 group.handle(http.MethodTrace, relativePath, handlers) 140 return group.returnObj() 141 } 142 143 func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain { 144 finalSize := len(group.Handlers) + len(handlers) 145 if finalSize >= int(abortIndex) { 146 panic("too many handlers") 147 } 148 mergedHandlers := make(HandlersChain, finalSize) 149 copy(mergedHandlers, group.Handlers) 150 copy(mergedHandlers[len(group.Handlers):], handlers) 151 return mergedHandlers 152 } 153 154 func (group *RouterGroup) calculateAbsolutePath(relativePath string) string { 155 return joinPaths(group.basePath, relativePath) 156 } 157 158 func (group *RouterGroup) returnObj() IRoutes { 159 if group.root { 160 return group.engine 161 } 162 return group 163 }