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  }