Skip to content

Commit

Permalink
added route params validator, see exemple 004
Browse files Browse the repository at this point in the history
  • Loading branch information
jchaput committed Jun 19, 2018
1 parent 32a062f commit 2d09f9f
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 39 deletions.
9 changes: 9 additions & 0 deletions bone.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Mux struct {
Routes map[string][]*Route
prefix string
notFound http.Handler
Validators map[string]Validator
Serve func(rw http.ResponseWriter, req *http.Request)
CaseSensitive bool
}
Expand All @@ -42,6 +43,14 @@ func New(adapters ...adapter) *Mux {
return m
}

// RegisterValidator makes the provided validator available to the routes register on that mux
func (m *Mux) RegisterValidator(name string, validator Validator) {
if m.Validators == nil {
m.Validators = make(map[string]Validator)
}
m.Validators[name] = validator
}

// Prefix set a default prefix for all routes registred on the router
func (m *Mux) Prefix(p string) *Mux {
m.prefix = strings.TrimSuffix(p, "/")
Expand Down
10 changes: 5 additions & 5 deletions bone_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ package bone
//
//// Test the ns/op
//func BenchmarkBoneMux(b *testing.B) {
// request, _ := http.NewRequest("GET", "/sd/test/1/root", nil)
// request, _ := http.NewRequest("GET", "/sd", nil)
// response := httptest.NewRecorder()
// muxx := New()
//
// muxx.Get("/", http.HandlerFunc(Bench))
// muxx.Get("/a", http.HandlerFunc(Bench))
// muxx.Get("/aas", http.HandlerFunc(Bench))
// muxx.Get("/sd/test/:id/root", http.HandlerFunc(Bench))
// muxx.Get("/sd", http.HandlerFunc(Bench))
//
// for n := 0; n < b.N; n++ {
// muxx.ServeHTTP(response, request)
Expand All @@ -32,14 +32,14 @@ package bone
//
//// Test httprouter ns/op
//func BenchmarkHttpRouterMux(b *testing.B) {
// request, _ := http.NewRequest("GET", "/sd/test/1/root", nil)
// request, _ := http.NewRequest("GET", "/sd", nil)
// response := httptest.NewRecorder()
// muxx := httprouter.New()
//
// muxx.Handler("GET", "/", http.HandlerFunc(Bench))
// muxx.Handler("GET", "/a", http.HandlerFunc(Bench))
// muxx.Handler("GET", "/aas", http.HandlerFunc(Bench))
// muxx.Handler("GET", "/sd/test/{:id}/root", http.HandlerFunc(Bench))
// muxx.Handler("GET", "/sd", http.HandlerFunc(Bench))
//
// for n := 0; n < b.N; n++ {
// muxx.ServeHTTP(response, request)
Expand Down Expand Up @@ -129,7 +129,7 @@ package bone
//func Bench(rw http.ResponseWriter, req *http.Request) {
// rw.Write([]byte("b"))
//}
//

/*
### Result ###
Expand Down
2 changes: 1 addition & 1 deletion bone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ func TestStandAloneRoute(t *testing.T) {
valid := false
mux := http.NewServeMux()

testRoute := NewRoute("/test", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
testRoute := NewRoute(nil, "/test", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
valid = true
}))
mux.Handle("/test", testRoute.Get())
Expand Down
15 changes: 12 additions & 3 deletions example/004/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@ package main
import (
"context"
"net/http"
"strconv"

"github.com/go-zoo/bone"
)

func main() {
mux := bone.New()
mux.CaseSensitive = true
mux.RegisterValidator("isNum", func(s string) bool {
if _, err := strconv.Atoi(s); err == nil {
return true
}
return false
})

mux.GetFunc("/ctx/:var", rootHandler)
mux.GetFunc("/ctx/:age|isNum/name/:name", rootHandler)

http.ListenAndServe(":8080", mux)
}
Expand All @@ -24,6 +31,8 @@ func rootHandler(rw http.ResponseWriter, req *http.Request) {
}

func subHandler(rw http.ResponseWriter, req *http.Request) {
val := req.Context().Value("var")
rw.Write([]byte(val.(string)))
vars := bone.GetAllValues(req)
age := vars["age"]
name := vars["name"]
rw.Write([]byte(age + " " + name))
}
4 changes: 2 additions & 2 deletions mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (m *Mux) NotFound(handler http.Handler) {

// Register the new route in the router with the provided method and handler
func (m *Mux) register(method string, path string, handler http.Handler) *Route {
r := NewRoute(m.prefix+path, handler)
r := NewRoute(m, m.prefix+path, handler)
r.Method = method
if valid(path) {
m.Routes[method] = append(m.Routes[method], r)
Expand All @@ -125,7 +125,7 @@ func (m *Mux) register(method string, path string, handler http.Handler) *Route

// SubRoute register a router as a SubRouter of bone
func (m *Mux) SubRoute(path string, router Router) *Route {
r := NewRoute(m.prefix+path, router)
r := NewRoute(m, m.prefix+path, router)
if valid(path) {
r.Atts += SUB
for _, mt := range method {
Expand Down
48 changes: 35 additions & 13 deletions route.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@ const (
// handler: is the handler who handle this route
// Method: define HTTP method on the route
type Route struct {
Path string
Method string
Size int
Atts int
wildPos int
Token Token
Pattern map[int]string
Compile map[int]*regexp.Regexp
Tag map[int]string
Handler http.Handler
Path string
Method string
Size int
Atts int
wildPos int
Token Token
Pattern map[int]string
Compile map[int]*regexp.Regexp
Tag map[int]string
Handler http.Handler
mux *Mux
validators map[string]string
}

// Token content all value of a spliting route path
Expand All @@ -55,8 +57,8 @@ type Token struct {
}

// NewRoute return a pointer to a Route instance and call save() on it
func NewRoute(url string, h http.Handler) *Route {
r := &Route{Path: url, Handler: h}
func NewRoute(mux *Mux, url string, h http.Handler) *Route {
r := &Route{Path: url, Handler: h, mux: mux}
r.save()
return r
}
Expand All @@ -72,6 +74,13 @@ func (r *Route) save() {
if r.Pattern == nil {
r.Pattern = make(map[int]string)
}
if idx, val := containsPipe(s); val != "" {
if r.validators == nil {
r.validators = make(map[string]string)
}
s = s[:idx]
r.validators[s[1:]] = val[1:]
}
r.Pattern[i] = s[1:]
r.Atts |= PARAM
case "#":
Expand Down Expand Up @@ -113,6 +122,11 @@ func (r *Route) matchAndParse(req *http.Request) (bool, map[string]string) {

vars := make(map[string]string, totalSize)
for k, v := range r.Pattern {
if validator := r.validators[v]; validator != "" {
if !(*r.mux).Validators[validator](ss[k]) {
return false, nil
}
}
vars[v], _ = url.QueryUnescape(ss[k])
}

Expand All @@ -128,7 +142,6 @@ func (r *Route) matchAndParse(req *http.Request) (bool, map[string]string) {
return true, vars
}
}

return false, nil
}

Expand Down Expand Up @@ -191,6 +204,15 @@ func (r *Route) exists(rw http.ResponseWriter, req *http.Request) bool {
return false
}

func containsPipe(src string) (int, string) {
for i, c := range src {
if c == '|' {
return i, src[i:]
}
}
return 0, ""
}

// Get set the route method to Get
func (r *Route) Get() *Route {
r.Method = "GET"
Expand Down
30 changes: 15 additions & 15 deletions route_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ func TestNewRoute(t *testing.T) {
args args
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewRoute(tt.args.url, tt.args.h); !reflect.DeepEqual(got, tt.want) {
if got := NewRoute(nil, tt.args.url, tt.args.h); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewRoute() = %v, want %v", got, tt.want)
}
})
Expand All @@ -45,7 +45,7 @@ func TestRoute_save(t *testing.T) {
name string
fields fields
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -88,7 +88,7 @@ func TestRoute_Match(t *testing.T) {
args args
want bool
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -134,7 +134,7 @@ func TestRoute_matchAndParse(t *testing.T) {
want bool
want1 map[string]string
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -184,7 +184,7 @@ func TestRoute_parse(t *testing.T) {
args args
want bool
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -229,7 +229,7 @@ func TestRoute_matchRawTokens(t *testing.T) {
args args
want bool
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -270,7 +270,7 @@ func TestRoute_Get(t *testing.T) {
fields fields
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -311,7 +311,7 @@ func TestRoute_Post(t *testing.T) {
fields fields
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -352,7 +352,7 @@ func TestRoute_Put(t *testing.T) {
fields fields
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -393,7 +393,7 @@ func TestRoute_Delete(t *testing.T) {
fields fields
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -434,7 +434,7 @@ func TestRoute_Head(t *testing.T) {
fields fields
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -475,7 +475,7 @@ func TestRoute_Patch(t *testing.T) {
fields fields
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -516,7 +516,7 @@ func TestRoute_Options(t *testing.T) {
fields fields
want *Route
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -561,7 +561,7 @@ func TestRoute_ServeHTTP(t *testing.T) {
fields fields
args args
}{
// TODO: Add test cases.
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package bone

// Validator can be passed to a route to validate the params
type Validator func(string) bool

0 comments on commit 2d09f9f

Please sign in to comment.