diff --git a/_future/macros_test.go b/_future/macros_test.go index 5634ba28..1b01f035 100644 --- a/_future/macros_test.go +++ b/_future/macros_test.go @@ -1,8 +1,19 @@ +// I would be grateful if I had the chance to see the whole work-in-progress in a codebase when I started. +// You have the chance to learn faster nowdays, don't underestimate that, that's the only reason that this "_future" folder exists now. +// +// The whole "router" package is a temp place to test my ideas and implementations for future iris' features. +// Young developers can understand and see how ideas can be transform to real implementations on a software like Iris, +// watching the history of a "dirty" code can be useful for some of you. + package router import ( "regexp" "testing" + + "gopkg.in/kataras/iris.v6" + "gopkg.in/kataras/iris.v6/adaptors/httprouter" + "gopkg.in/kataras/iris.v6/httptest" ) // macros should be registered before .Listen @@ -30,7 +41,7 @@ func fromRegexp(expr string) func(paramValue string) bool { // link the path tmpl with macros, at .Boot time, before Listen. // make it a as middleware from the beginning and prepend that before the main handler. -func link(path string, m _macros) { +func link(path string, mac _macros) iris.HandlerFunc { tmpl, err := ParsePath(path) if err != nil { panic(err) @@ -39,8 +50,45 @@ func link(path string, m _macros) { // and return a new compiled macro or a list of iris handlers // in order to be prepended on the original route or make a different function for that? // we'll see. - _ = tmpl + var h iris.HandlerFunc // we could add an empty handler but we wouldn't know where to ctx.Next if this path doesn't uses macros. + + createH := func(paramName string, validator func(string) bool, failStatus int, prevH iris.HandlerFunc) iris.HandlerFunc { + return func(ctx *iris.Context) { + if prevH != nil { + prevH(ctx) + } + + paramValue := ctx.Param(paramName) + if paramValue != "" { + valid := validator(paramValue) + if !valid { + ctx.EmitError(failStatus) + return + } + } + // println(ctx.Pos) + // remember: router already matches the path, so here if a path param is missing then it was allowed by the router. + ctx.Next() + } + } + + for i := range tmpl.Params { + p := tmpl.Params[i] + if m := mac[p.Param.Macro.Name]; m != nil { + prevH := h + h = createH(p.Param.Name, m, p.Param.FailStatusCode, prevH) + } + } + + if h == nil { + // println("h is nil") + return func(ctx *iris.Context) { + ctx.Next() // is ok, the route doesn't contains any valid macros + } + } + + return h } // eval runs while serving paths @@ -57,19 +105,28 @@ func link(path string, m _macros) { // only for test-cases? and after on iris we can make a middleware from this, I should think it more when I stop the drinking. func testMacros(source string) error { - var m = _macros{ - "id": fromRegexp("[1-9]+$"), - } - - link(source, m) - - // eval("/api/users/42", result) - return nil } func TestMacros(t *testing.T) { - if err := testMacros("/api/users/{id:int}/posts"); err != nil { - t.Fatal(err) + var m = _macros{ + "int": fromRegexp("[1-9]+$"), } + path := "/api/users/{id:int}/posts" + app := iris.New() + app.Adapt(httprouter.New()) + + hv := link(path, m) + + app.Get("/api/users/:id/posts", hv, func(ctx *iris.Context) { + ctx.ResponseWriter.WriteString(ctx.Path()) + }) + + e := httptest.New(app, t) + + e.GET("/api/users/42/posts").Expect().Status(iris.StatusOK).Body().Equal("/api/users/42/posts") + e.GET("/api/users/0/posts").Expect().Status(iris.StatusNotFound) + e.GET("/api/users/_/posts").Expect().Status(iris.StatusNotFound) + e.GET("/api/users/s/posts").Expect().Status(iris.StatusNotFound) + e.GET("/api/users/posts").Expect().Status(iris.StatusNotFound) } diff --git a/_future/param_parser.go b/_future/param_parser.go index 49ed72c8..d2bc4e83 100644 --- a/_future/param_parser.go +++ b/_future/param_parser.go @@ -43,7 +43,7 @@ const ( ANDSymbol = '&' ) -const DefaultFailStatusCode = 0 +const DefaultFailStatusCode = 404 // Parse i.e: // id:int range(1,5) otherFunc(3) !404