Fixes pipeline API

This commit is contained in:
Manu Mtz-Almeida 2015-06-11 01:02:38 +02:00
parent 86c75ce95d
commit 4998bc2b2e
3 changed files with 84 additions and 35 deletions

4
gin.go
View File

@ -71,6 +71,7 @@ func New() *Engine {
RouterGroup: RouterGroup{
Handlers: nil,
BasePath: "/",
root: true,
},
RedirectTrailingSlash: true,
RedirectFixedPath: false,
@ -133,10 +134,11 @@ func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
// Attachs a global middleware to the router. ie. the middlewares attached though Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middlewares ...HandlerFunc) {
func (engine *Engine) Use(middlewares ...HandlerFunc) routesInterface {
engine.RouterGroup.Use(middlewares...)
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}
func (engine *Engine) rebuild404Handlers() {

View File

@ -11,17 +11,37 @@ import (
"strings"
)
type routesInterface interface {
Use(...HandlerFunc) routesInterface
Handle(string, string, ...HandlerFunc) routesInterface
Any(string, ...HandlerFunc) routesInterface
GET(string, ...HandlerFunc) routesInterface
POST(string, ...HandlerFunc) routesInterface
DELETE(string, ...HandlerFunc) routesInterface
PATCH(string, ...HandlerFunc) routesInterface
PUT(string, ...HandlerFunc) routesInterface
OPTIONS(string, ...HandlerFunc) routesInterface
HEAD(string, ...HandlerFunc) routesInterface
StaticFile(string, string) routesInterface
Static(string, string) routesInterface
StaticFS(string, http.FileSystem) routesInterface
}
// Used internally to configure router, a RouterGroup is associated with a prefix
// and an array of handlers (middlewares)
type RouterGroup struct {
Handlers HandlersChain
BasePath string
engine *Engine
root bool
}
// Adds middlewares to the group, see example code in github.
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
func (group *RouterGroup) Use(middlewares ...HandlerFunc) routesInterface {
group.Handlers = append(group.Handlers, middlewares...)
return group.returnObj()
}
// Creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
@ -44,64 +64,56 @@ func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *R
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) {
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) routesInterface {
absolutePath := group.calculateAbsolutePath(relativePath)
handlers = group.combineHandlers(handlers)
group.engine.addRoute(httpMethod, absolutePath, handlers)
return group.returnObj()
}
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) *RouterGroup {
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) routesInterface {
if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil {
panic("http method " + httpMethod + " is not valid")
}
group.handle(httpMethod, relativePath, handlers)
return group
return group.handle(httpMethod, relativePath, handlers)
}
// POST is a shortcut for router.Handle("POST", path, handle)
func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) *RouterGroup {
group.handle("POST", relativePath, handlers)
return group
func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) routesInterface {
return group.handle("POST", relativePath, handlers)
}
// GET is a shortcut for router.Handle("GET", path, handle)
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) *RouterGroup {
group.handle("GET", relativePath, handlers)
return group
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) routesInterface {
return group.handle("GET", relativePath, handlers)
}
// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) *RouterGroup {
group.handle("DELETE", relativePath, handlers)
return group
func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) routesInterface {
return group.handle("DELETE", relativePath, handlers)
}
// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) *RouterGroup {
group.handle("PATCH", relativePath, handlers)
return group
func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) routesInterface {
return group.handle("PATCH", relativePath, handlers)
}
// PUT is a shortcut for router.Handle("PUT", path, handle)
func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) *RouterGroup {
group.handle("PUT", relativePath, handlers)
return group
func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) routesInterface {
return group.handle("PUT", relativePath, handlers)
}
// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) *RouterGroup {
group.handle("OPTIONS", relativePath, handlers)
return group
func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) routesInterface {
return group.handle("OPTIONS", relativePath, handlers)
}
// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) *RouterGroup {
group.handle("HEAD", relativePath, handlers)
return group
func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) routesInterface {
return group.handle("HEAD", relativePath, handlers)
}
func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) *RouterGroup {
func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) routesInterface {
// GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE
group.handle("GET", relativePath, handlers)
group.handle("POST", relativePath, handlers)
@ -112,10 +124,10 @@ func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) *Rou
group.handle("DELETE", relativePath, handlers)
group.handle("CONNECT", relativePath, handlers)
group.handle("TRACE", relativePath, handlers)
return group
return group.returnObj()
}
func (group *RouterGroup) StaticFile(relativePath, filepath string) *RouterGroup {
func (group *RouterGroup) StaticFile(relativePath, filepath string) routesInterface {
if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
panic("URL parameters can not be used when serving a static file")
}
@ -124,7 +136,7 @@ func (group *RouterGroup) StaticFile(relativePath, filepath string) *RouterGroup
}
group.GET(relativePath, handler)
group.HEAD(relativePath, handler)
return group
return group.returnObj()
}
// Static serves files from the given file system root.
@ -133,11 +145,11 @@ func (group *RouterGroup) StaticFile(relativePath, filepath string) *RouterGroup
// To use the operating system's file system implementation,
// use :
// router.Static("/static", "/var/www")
func (group *RouterGroup) Static(relativePath, root string) *RouterGroup {
func (group *RouterGroup) Static(relativePath, root string) routesInterface {
return group.StaticFS(relativePath, Dir(root, false))
}
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) *RouterGroup {
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) routesInterface {
if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
panic("URL parameters can not be used when serving a static folder")
}
@ -147,7 +159,7 @@ func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) *Rou
// Register GET and HEAD handlers
group.GET(urlPattern, handler)
group.HEAD(urlPattern, handler)
return group
return group.returnObj()
}
func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
@ -176,3 +188,11 @@ func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain
func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
return joinPaths(group.BasePath, relativePath)
}
func (group *RouterGroup) returnObj() routesInterface {
if group.root {
return group.engine
} else {
return group
}
}

View File

@ -148,3 +148,30 @@ func TestRouterGroupBadMethod(t *testing.T) {
router.Handle("PATCh", "/")
})
}
func TestRouterGroupPipeline(t *testing.T) {
router := New()
testRoutesInterface(t, router)
v1 := router.Group("/v1")
testRoutesInterface(t, v1)
}
func testRoutesInterface(t *testing.T, r routesInterface) {
handler := func(c *Context) {}
assert.Equal(t, r, r.Use(handler))
assert.Equal(t, r, r.Handle("GET", "/handler", handler))
assert.Equal(t, r, r.Any("/any", handler))
assert.Equal(t, r, r.GET("/", handler))
assert.Equal(t, r, r.POST("/", handler))
assert.Equal(t, r, r.DELETE("/", handler))
assert.Equal(t, r, r.PATCH("/", handler))
assert.Equal(t, r, r.PUT("/", handler))
assert.Equal(t, r, r.OPTIONS("/", handler))
assert.Equal(t, r, r.HEAD("/", handler))
assert.Equal(t, r, r.StaticFile("/file", "."))
assert.Equal(t, r, r.Static("/static", "."))
assert.Equal(t, r, r.StaticFS("/static2", Dir(".", false)))
}