mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
_future
Former-commit-id: 969ab7495c421cb8a108a6821c22663f6eb12b11
This commit is contained in:
parent
a769d54471
commit
00cfdf404a
|
@ -19,7 +19,7 @@ import (
|
||||||
|
|
||||||
// a helper to return a macro from a simple regexp
|
// a helper to return a macro from a simple regexp
|
||||||
// it compiles the regexp and after returns the macro, for obviously performance reasons.
|
// it compiles the regexp and after returns the macro, for obviously performance reasons.
|
||||||
func fromRegexp(expr string) func(paramValue string) bool {
|
func fromRegexp(expr string) _macrofn {
|
||||||
if expr == "" {
|
if expr == "" {
|
||||||
panic("empty expr on regex")
|
panic("empty expr on regex")
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ func fromRegexp(expr string) func(paramValue string) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return r.MatchString
|
return func(pathParamValue string, _ *iris.Context) bool { return r.MatchString(pathParamValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// link the path tmpl with macros, at .Boot time, before Listen.
|
// link the path tmpl with macros, at .Boot time, before Listen.
|
||||||
|
@ -50,22 +50,21 @@ func link(path string, mac _macros) iris.HandlerFunc {
|
||||||
|
|
||||||
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.
|
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 {
|
createH := func(paramName string, validator _macrofn, failStatus int, prevH iris.HandlerFunc) iris.HandlerFunc {
|
||||||
return func(ctx *iris.Context) {
|
return func(ctx *iris.Context) {
|
||||||
if prevH != nil {
|
if prevH != nil {
|
||||||
prevH(ctx)
|
prevH(ctx)
|
||||||
}
|
}
|
||||||
paramValue := ctx.Param(paramName)
|
paramValue := ctx.Param(paramName)
|
||||||
if paramValue != "" {
|
if paramValue != "" {
|
||||||
valid := validator(paramValue)
|
valid := validator(paramValue, ctx)
|
||||||
if !valid {
|
if !valid {
|
||||||
print("not valid for validator on paramValue= '" + paramValue + "' ctx.Pos = ")
|
// print("not valid for validator on paramValue= '" + paramValue + "' ctx.Pos = ")
|
||||||
println(ctx.Pos) // it should be always 0.
|
// println(ctx.Pos) // it should be always 0.
|
||||||
ctx.EmitError(failStatus)
|
ctx.EmitError(failStatus)
|
||||||
return
|
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.
|
// remember: router already matches the path, so here if a path param is missing then it was allowed by the router.
|
||||||
ctx.Next()
|
ctx.Next()
|
||||||
}
|
}
|
||||||
|
@ -77,28 +76,28 @@ func link(path string, mac _macros) iris.HandlerFunc {
|
||||||
prevH := h
|
prevH := h
|
||||||
eval := m.eval
|
eval := m.eval
|
||||||
for _, fi := range m.funcs {
|
for _, fi := range m.funcs {
|
||||||
println("details for: " + fi.name)
|
|
||||||
println("m.funcs len = ")
|
|
||||||
print(len(m.funcs))
|
|
||||||
println("vs tmpl macro's funcs len = ")
|
|
||||||
print(len(p.Param.Macro.Funcs))
|
|
||||||
println()
|
|
||||||
for _, mi := range p.Param.Macro.Funcs {
|
for _, mi := range p.Param.Macro.Funcs {
|
||||||
|
hasFunc := fi.name == mi.Name
|
||||||
|
if !hasFunc {
|
||||||
|
for _, gb := range mac[global_macro].funcs {
|
||||||
|
if gb.name == fi.name {
|
||||||
|
hasFunc = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if fi.name == mi.Name {
|
if hasFunc {
|
||||||
println(fi.name + " matches with pathtmpl macro func: " + mi.Name)
|
|
||||||
prevEval := eval
|
prevEval := eval
|
||||||
macroFuncEval := fi.eval(mi.Params)
|
macroFuncEval := fi.eval(mi.Params)
|
||||||
eval = func(pvalue string) bool {
|
eval = func(pvalue string, ctx *iris.Context) bool {
|
||||||
if prevEval(pvalue) {
|
if prevEval(pvalue, ctx) {
|
||||||
return macroFuncEval(pvalue)
|
return macroFuncEval(pvalue, ctx)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
println("fi.name = " + fi.name + " | mi.Name = " + mi.Name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,13 +132,17 @@ func testMacros(source string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let's give the macro's funcs access to context, it will be great experimental to serve templates just with a path signature
|
||||||
|
type _macrofn func(pathParamValue string, ctx *iris.Context) bool
|
||||||
|
|
||||||
type _macrofunc struct {
|
type _macrofunc struct {
|
||||||
name string
|
name string
|
||||||
eval func([]string) func(string) bool
|
eval func([]string) _macrofn
|
||||||
}
|
}
|
||||||
|
|
||||||
type _macro struct {
|
type _macro struct {
|
||||||
funcs []_macrofunc
|
funcs []_macrofunc
|
||||||
eval func(string) bool
|
eval _macrofn
|
||||||
}
|
}
|
||||||
|
|
||||||
// macros should be registered before .Listen
|
// macros should be registered before .Listen
|
||||||
|
@ -147,20 +150,23 @@ type _macros map[string]*_macro
|
||||||
|
|
||||||
var all_macros = _macros{}
|
var all_macros = _macros{}
|
||||||
|
|
||||||
func addMacro(name string, v func(string) bool) {
|
func addMacro(name string, v _macrofn) {
|
||||||
all_macros[name] = &_macro{eval: v}
|
all_macros[name] = &_macro{eval: v}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addMacroFunc(macroName string, funcName string, v func([]string) func(string) bool) {
|
func addMacroFunc(macroName string, funcName string, v func([]string) _macrofn) {
|
||||||
if m, found := all_macros[macroName]; found {
|
if m, found := all_macros[macroName]; found {
|
||||||
m.funcs = append(m.funcs, _macrofunc{name: funcName, eval: v})
|
m.funcs = append(m.funcs, _macrofunc{name: funcName, eval: v})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const global_macro = "any"
|
||||||
|
|
||||||
func TestMacros(t *testing.T) {
|
func TestMacros(t *testing.T) {
|
||||||
addMacro("int", fromRegexp("[1-9]+$"))
|
addMacro("int", fromRegexp("[1-9]+$"))
|
||||||
|
|
||||||
// {id:int range(42,49)}
|
// {id:int range(42,49)}
|
||||||
addMacroFunc("int", "range", func(params []string) func(string) bool {
|
addMacroFunc("int", "range", func(params []string) _macrofn {
|
||||||
// start: .Boot time, before .Listen
|
// start: .Boot time, before .Listen
|
||||||
allowedParamsLen := 2
|
allowedParamsLen := 2
|
||||||
// params: 42,49 (including first and second)
|
// params: 42,49 (including first and second)
|
||||||
|
@ -178,44 +184,85 @@ func TestMacros(t *testing.T) {
|
||||||
}
|
}
|
||||||
// end
|
// end
|
||||||
|
|
||||||
return func(paramValue string) bool {
|
return func(paramValue string, _ *iris.Context) bool {
|
||||||
paramValueInt, err := strconv.Atoi(paramValue)
|
paramValueInt, err := strconv.Atoi(paramValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
print("min: ")
|
|
||||||
println(min)
|
|
||||||
print("max: ")
|
|
||||||
println(max)
|
|
||||||
print("value: ")
|
|
||||||
println(paramValueInt)
|
|
||||||
if paramValueInt >= min && paramValueInt <= max {
|
if paramValueInt >= min && paramValueInt <= max {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
path := "/api/users/{id:int range(42,49)}/posts"
|
addMacroFunc("int", "even", func(params []string) _macrofn {
|
||||||
|
return func(paramValue string, _ *iris.Context) bool {
|
||||||
|
paramValueInt, err := strconv.Atoi(paramValue)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if paramValueInt%2 == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// "any" will contain macros functions
|
||||||
|
// which are available to all other, we will need some functions to be 'globally' registered when don't care about
|
||||||
|
// what macro is used, for example let's try the markdown(#hello), yes serve files without even call a function:)
|
||||||
|
addMacro("any", fromRegexp(".*"))
|
||||||
|
addMacroFunc("any", "markdown", func(params []string) _macrofn {
|
||||||
|
if len(params) != 1 {
|
||||||
|
panic("markdown expected 1 arg")
|
||||||
|
}
|
||||||
|
|
||||||
|
contents := params[0]
|
||||||
|
// we don't care about path's parameter here
|
||||||
|
return func(_ string, ctx *iris.Context) bool {
|
||||||
|
println("print markdown?: ")
|
||||||
|
ctx.Markdown(iris.StatusOK, contents)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
path := "/api/users/{id:int range(42,49) even() !600}/posts"
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
app.Adapt(httprouter.New())
|
app.Adapt(httprouter.New())
|
||||||
|
|
||||||
hv := link(path, all_macros)
|
hv := link(path, all_macros)
|
||||||
|
// 600 is a custom virtual error code to handle "int" param invalids
|
||||||
|
// it sends a custom error message with a 404 (not found) http status code.
|
||||||
|
app.OnError(600, func(ctx *iris.Context) {
|
||||||
|
ctx.SetStatusCode(404) // throw a raw 404 not found
|
||||||
|
ctx.Writef("Expecting an integer in range between and 42-49, should be even number too")
|
||||||
|
// println("600 -> 404 from " + ctx.Path())
|
||||||
|
})
|
||||||
app.Get("/api/users/:id/posts", hv, func(ctx *iris.Context) {
|
app.Get("/api/users/:id/posts", hv, func(ctx *iris.Context) {
|
||||||
ctx.ResponseWriter.WriteString(ctx.Path())
|
ctx.ResponseWriter.WriteString(ctx.Path())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
path2 := "/markdown/{anything:any markdown(**hello**)}"
|
||||||
|
hv2 := link(path2, all_macros)
|
||||||
|
app.Get("/markdown/*anything", hv2)
|
||||||
|
|
||||||
e := httptest.New(app, t)
|
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/42/posts").Expect().Status(iris.StatusOK).Body().Equal("/api/users/42/posts")
|
||||||
e.GET("/api/users/50/posts").Expect().Status(iris.StatusNotFound) // remember, it accepts 1-9 not matched if zero.
|
e.GET("/api/users/50/posts").Expect().Status(iris.StatusNotFound).Body().Equal("Expecting an integer in range between and 42-49, should be even number too") // remember, it accepts 1-9 not matched if zero.
|
||||||
e.GET("/api/users/0/posts").Expect().Status(iris.StatusNotFound)
|
e.GET("/api/users/0/posts").Expect().Status(iris.StatusNotFound)
|
||||||
e.GET("/api/users/_/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/s/posts").Expect().Status(iris.StatusNotFound)
|
||||||
e.GET("/api/users/posts").Expect().Status(iris.StatusNotFound)
|
e.GET("/api/users/posts").Expect().Status(iris.StatusNotFound)
|
||||||
// macro func invalidate test with a non-zero value between 1-9 but bigger than the max(49)
|
// macro func invalidate test with a non-zero value between 1-9 but bigger than the max(49)
|
||||||
e.GET("/api/users/51/posts").Expect().Status(iris.StatusNotFound)
|
e.GET("/api/users/51/posts").Expect().Status(iris.StatusNotFound)
|
||||||
|
// macro func invalidate "even" with a non-zero value but 49 is not an even number
|
||||||
|
e.GET("/api/users/49/posts").Expect().Status(iris.StatusNotFound)
|
||||||
|
|
||||||
|
// test any and global
|
||||||
|
// response with "path language" only no need of handler too.
|
||||||
|
// As it goes I love the idea and users will embrace and built awesome things on top of it.
|
||||||
|
// maybe I have to 'rename' the final feature on something like iris expression language and document it as much as I can, people will love that
|
||||||
|
e.GET("/markdown/something").Expect().Status(iris.StatusOK).ContentType("text/html", "utf-8").Body().Equal("<p><strong>hello</strong></p>\n")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user