-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Integrate and adapt julienschmidt/httprouter#89
- Loading branch information
Olivier Poitrey
committed
Dec 13, 2015
1 parent
161ec6b
commit 98bd70d
Showing
5 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package xmux | ||
|
||
import "github.com/rs/xhandler" | ||
|
||
// Group makes it simple to configure a group of routes with the | ||
// same prefix. | ||
type Group struct { | ||
m *Mux | ||
p string | ||
} | ||
|
||
func newRouteGroup(mux *Mux, path string) *Group { | ||
if path[0] != '/' { | ||
panic("path must begin with '/' in path '" + path + "'") | ||
} | ||
|
||
//Strip traling / (if present) as all added sub paths must start with a / | ||
if path[len(path)-1] == '/' { | ||
path = path[:len(path)-1] | ||
} | ||
return &Group{m: mux, p: path} | ||
} | ||
|
||
// NewGroup creates a new routes group with the provided path prefix. | ||
// All routes added to the returned group will have the path prepended. | ||
func (g *Group) NewGroup(path string) *Group { | ||
return newRouteGroup(g.m, g.subPath(path)) | ||
} | ||
|
||
// GET is a shortcut for g.Handle("GET", path, handler) | ||
func (g *Group) GET(path string, handler xhandler.HandlerC) { | ||
g.Handle("GET", path, handler) | ||
} | ||
|
||
// HEAD is a shortcut for g.Handle("HEAD", path, handler) | ||
func (g *Group) HEAD(path string, handler xhandler.HandlerC) { | ||
g.Handle("HEAD", path, handler) | ||
} | ||
|
||
// OPTIONS is a shortcut for g.Handle("OPTIONS", path, handler) | ||
func (g *Group) OPTIONS(path string, handler xhandler.HandlerC) { | ||
g.Handle("OPTIONS", path, handler) | ||
} | ||
|
||
// POST is a shortcut for g.Handle("POST", path, handler) | ||
func (g *Group) POST(path string, handler xhandler.HandlerC) { | ||
g.Handle("POST", path, handler) | ||
} | ||
|
||
// PUT is a shortcut for g.Handle("PUT", path, handler) | ||
func (g *Group) PUT(path string, handler xhandler.HandlerC) { | ||
g.Handle("PUT", path, handler) | ||
} | ||
|
||
// PATCH is a shortcut for g.Handle("PATCH", path, handler) | ||
func (g *Group) PATCH(path string, handler xhandler.HandlerC) { | ||
g.Handle("PATCH", path, handler) | ||
} | ||
|
||
// DELETE is a shortcut for g.Handle("DELETE", path, handler) | ||
func (g *Group) DELETE(path string, handler xhandler.HandlerC) { | ||
g.Handle("DELETE", path, handler) | ||
} | ||
|
||
// Handle registers a new request handle with the given path and method. | ||
// | ||
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut | ||
// functions can be used. | ||
// | ||
// 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 (g *Group) Handle(method, path string, handler xhandler.HandlerC) { | ||
g.m.Handle(method, g.subPath(path), handler) | ||
} | ||
|
||
func (g *Group) subPath(path string) string { | ||
if path[0] != '/' { | ||
panic("path must start with a '/'") | ||
} | ||
return g.p + path | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package xmux_test | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/rs/xhandler" | ||
"github.com/rs/xhandler/xmux" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
func ExampleMux_NewGroup() { | ||
mux := xmux.New() | ||
|
||
api := mux.NewGroup("/api") | ||
|
||
api.GET("/users/:name", xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "GET /api/users/%s", xmux.Params(ctx).Get("name")) | ||
})) | ||
|
||
api.POST("/users/:name", xhandler.HandlerFuncC(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { | ||
fmt.Fprintf(w, "POST /api/users/%s", xmux.Params(ctx).Get("name")) | ||
})) | ||
|
||
if err := http.ListenAndServe(":8080", xhandler.New(context.Background(), mux)); err != nil { | ||
log.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package xmux | ||
|
||
import ( | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/rs/xhandler" | ||
"github.com/stretchr/testify/assert" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
func TestRouteGroupOfARouteGroup(t *testing.T) { | ||
var get bool | ||
mux := New() | ||
foo := mux.NewGroup("/foo") // creates /foo group | ||
bar := foo.NewGroup("/bar") | ||
|
||
bar.GET("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
get = true | ||
})) | ||
|
||
w := new(mockResponseWriter) | ||
r, _ := http.NewRequest("GET", "/foo/bar/GET", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, get, "routing GET /foo/bar/GET failed") | ||
} | ||
|
||
func TestRouteNewGroupStripTrailingSlash(t *testing.T) { | ||
var get bool | ||
mux := New() | ||
foo := mux.NewGroup("/foo/") | ||
|
||
foo.GET("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
get = true | ||
})) | ||
|
||
w := new(mockResponseWriter) | ||
r, _ := http.NewRequest("GET", "/foo/GET", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, get, "routing GET /foo/GET failed") | ||
} | ||
|
||
func TestRouteNewGroupError(t *testing.T) { | ||
mux := New() | ||
assert.Panics(t, func() { | ||
mux.NewGroup("foo") | ||
}) | ||
assert.Panics(t, func() { | ||
mux.NewGroup("/foo").NewGroup("bar") | ||
}) | ||
} | ||
|
||
func TestRouteGroupAPI(t *testing.T) { | ||
var get, head, options, post, put, patch, delete bool | ||
|
||
mux := New() | ||
group := mux.NewGroup("/foo") // creates /foo group | ||
|
||
group.GET("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
get = true | ||
})) | ||
group.HEAD("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
head = true | ||
})) | ||
group.OPTIONS("/GET", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
options = true | ||
})) | ||
group.POST("/POST", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
post = true | ||
})) | ||
group.PUT("/PUT", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
put = true | ||
})) | ||
group.PATCH("/PATCH", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
patch = true | ||
})) | ||
group.DELETE("/DELETE", xhandler.HandlerFuncC(func(_ context.Context, _ http.ResponseWriter, _ *http.Request) { | ||
delete = true | ||
})) | ||
|
||
w := new(mockResponseWriter) | ||
|
||
r, _ := http.NewRequest("GET", "/foo/GET", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, get, "routing /foo/GET failed") | ||
|
||
r, _ = http.NewRequest("HEAD", "/foo/GET", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, head, "routing /foo/GET failed") | ||
|
||
r, _ = http.NewRequest("OPTIONS", "/foo/GET", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, options, "routing /foo/GET failed") | ||
|
||
r, _ = http.NewRequest("POST", "/foo/POST", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, post, "routing /foo/POST failed") | ||
|
||
r, _ = http.NewRequest("PUT", "/foo/PUT", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, put, "routing /foo/PUT failed") | ||
|
||
r, _ = http.NewRequest("PATCH", "/foo/PATCH", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, patch, "routing /foo/PATCH failed") | ||
|
||
r, _ = http.NewRequest("DELETE", "/foo/DELETE", nil) | ||
mux.ServeHTTPC(context.Background(), w, r) | ||
assert.True(t, delete, "routing /foo/DELETE failed") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters