diff --git a/_examples/README.md b/_examples/README.md index 289a193b..139937fb 100644 --- a/_examples/README.md +++ b/_examples/README.md @@ -43,6 +43,7 @@ * Middleware * [Per Route](routing/writing-a-middleware/per-route/main.go) * [Globally](routing/writing-a-middleware/globally/main.go) + * [Handlers Execution Rule](routing/route-handlers-execution-rules/main.go) * [Route Register Rule](routing/route-register-rule/main.go) * Convert net/http Handlers * [From func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)](convert-handlers/negroni-like/main.go) diff --git a/_examples/mvc/middleware/without-ctx-next/main.go b/_examples/mvc/middleware/without-ctx-next/main.go index b29e803c..1473880e 100644 --- a/_examples/mvc/middleware/without-ctx-next/main.go +++ b/_examples/mvc/middleware/without-ctx-next/main.go @@ -1,26 +1,7 @@ -/*Package main is a simple example of the behavior change of the execution flow of the handlers, -normally we need the `ctx.Next()` to call the next handler in a route's handler chain, -but with the new `ExecutionRules` we can change this default behavior. -Please read below before continue. +/*Package main shows how to add done handlers in an MVC application without +the necessity of `ctx.Next()` inside the controller's methods. -The `Party#SetExecutionRules` alters the execution flow of the route handlers outside of the handlers themselves. - -For example, if for some reason the desired result is the (done or all) handlers to be executed no matter what -even if no `ctx.Next()` is called in the previous handlers, including the begin(`Use`), -the main(`Handle`) and the done(`Done`) handlers themselves, then: -Party#SetExecutionRules(iris.ExecutionRules { - Begin: iris.ExecutionOptions{Force: true}, - Main: iris.ExecutionOptions{Force: true}, - Done: iris.ExecutionOptions{Force: true}, -}) - -Note that if `true` then the only remained way to "break" the handler chain is by `ctx.StopExecution()` now that `ctx.Next()` does not matter. - -These rules are per-party, so if a `Party` creates a child one then the same rules will be applied to that as well. -Reset of these rules (before `Party#Handle`) can be done with `Party#SetExecutionRules(iris.ExecutionRules{})`. - -The most common scenario for its use can be found inside Iris MVC Applications; -when we want the `Done` handlers of that specific mvc app's `Party` +When we want the `Done` handlers of that specific mvc app's `Party` to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`*/ package main @@ -33,23 +14,17 @@ func main() { app := iris.New() app.Get("/", func(ctx iris.Context) { ctx.Redirect("/example") }) - // example := app.Party("/example") - // example.SetExecutionRules && mvc.New(example) or... - m := mvc.New(app.Party("/example")) + exampleRouter := app.Party("/example") + { + exampleRouter.SetExecutionRules(iris.ExecutionRules{ + Done: iris.ExecutionOptions{Force: true}, + }) - // IMPORTANT - // All options can be filled with Force:true, they all play nice together. - m.Router.SetExecutionRules(iris.ExecutionRules{ - // Begin: <- from `Use[all]` to `Handle[last]` future route handlers, execute all, execute all even if `ctx.Next()` is missing. - // Main: <- all `Handle` future route handlers, execute all >> >>. - Done: iris.ExecutionOptions{Force: true}, // <- from `Handle[last]` to `Done[all]` future route handlers, execute all >> >>. - }) - m.Router.Done(doneHandler) - // m.Router.Done(...) - // ... - // + exampleRouter.Done(doneHandler) - m.Handle(&exampleController{}) + m := mvc.New(exampleRouter) + m.Handle(&exampleController{}) + } app.Listen(":8080") } @@ -64,7 +39,8 @@ func (c *exampleController) Get() string { return "From Main Handler" // Note that here we don't binding the `Context`, and we don't call its `Next()` // function in order to call the `doneHandler`, - // this is done automatically for us because we changed the execution rules with the `SetExecutionRules`. + // this is done automatically for us because we changed the execution rules with the + // `SetExecutionRules`. // // Therefore the final output is: // From Main Handler diff --git a/_examples/routing/route-handlers-execution-rules/main.go b/_examples/routing/route-handlers-execution-rules/main.go new file mode 100644 index 00000000..5b503b7e --- /dev/null +++ b/_examples/routing/route-handlers-execution-rules/main.go @@ -0,0 +1,61 @@ +/*Package main is a simple example of the behavior change of the execution flow of the handlers, +normally we need the `ctx.Next()` to call the next handler in a route's handler chain, +but with the `ExecutionRules` we can change this default behavior. +Please read below before continue. + +The `Party#SetExecutionRules` alters the execution flow of the route handlers. + +For example, if for some reason the desired result is the (done or all) handlers +to be executed no matter what, even if no `ctx.Next()` is called in the previous handlers: + +app.SetExecutionRules(iris.ExecutionRules { + Begin: iris.ExecutionOptions{Force: true}, # begin handlers(.Use) + Main: iris.ExecutionOptions{Force: true}, # main handler (.Handle/Get...) + Done: iris.ExecutionOptions{Force: true}, # done handlers (.Done) +}) + +Note that if `true` then the only remained way to "break" the handler chain +is by calling the `ctx.StopExecution()` (now that `ctx.Next()` doesn't even matter). + +These rules are per-party, so if a `Party` creates a child one then +the same rules will be applied to that as well. + +Reset of these rules to their defaults (before `Party#Handle`) can be done +with `Party#SetExecutionRules(iris.ExecutionRules{})`. + +*/ +package main + +import "github.com/kataras/iris/v12" + +func main() { + app := iris.New() + + app.SetExecutionRules(iris.ExecutionRules{ + // * From `Use[all]` to `Handle[last]` future route handlers, + // execute all (even if `ctx.Next()` is missing): + // Begin: true, + // + // * All `Handle` future route handlers, execute all: + // Main: true, + // + // * From `Handle[last]` to `Done[last]` future route handlers, execute all: + Done: iris.ExecutionOptions{Force: true}, + }) + app.Done(doneHandler) + + app.Get("/", mainHandler) + + // http://localhost:8080 + app.Listen(":8080") +} + +func mainHandler(ctx iris.Context) { + ctx.WriteString("From Main Handler\n") + // ctx.Next() is not required now that we have declared + // Done: iris.ExecutionOptions{Force: true}. +} + +func doneHandler(ctx iris.Context) { + ctx.WriteString("From Done Handler\n") +} diff --git a/_examples/routing/writing-a-middleware/globally/main.go b/_examples/routing/writing-a-middleware/globally/main.go index 3bb50926..2cd92e94 100644 --- a/_examples/routing/writing-a-middleware/globally/main.go +++ b/_examples/routing/writing-a-middleware/globally/main.go @@ -22,7 +22,7 @@ func main() { // are applied to existing routes and future routes. // // Remember: the `Use` and `Done` are applied to the current party's and its children, - // so if we used the `app.Use/Don`e before the routes registration + // so if we used the `app.Use/Done` before the routes registration // it would work like UseGlobal/DoneGlobal in this case, because the `app` is the root party. // // See `app.Party/PartyFunc` for more. diff --git a/context/context.go b/context/context.go index d39e2dba..b3e6de2b 100644 --- a/context/context.go +++ b/context/context.go @@ -1513,7 +1513,7 @@ func DefaultNext(ctx Context) { // it should be used inside a middleware. // // Note: Custom context should override this method in order to be able to pass its own context.Context implementation. -func (ctx *context) Next() { // or context.Next(ctx) +func (ctx *context) Next() { Next(ctx) }