Skip to content

Commit

Permalink
add route-handlers-execution-rules example
Browse files Browse the repository at this point in the history
Former-commit-id: 95e3dfad33b98d20b761ea1d06dee8df91c3632d
  • Loading branch information
kataras committed Jun 16, 2020
1 parent 7e98555 commit 6557dcf
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 40 deletions.
1 change: 1 addition & 0 deletions _examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
52 changes: 14 additions & 38 deletions _examples/mvc/middleware/without-ctx-next/main.go
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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")
}
Expand All @@ -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
Expand Down
61 changes: 61 additions & 0 deletions _examples/routing/route-handlers-execution-rules/main.go
Original file line number Diff line number Diff line change
@@ -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")
}
2 changes: 1 addition & 1 deletion _examples/routing/writing-a-middleware/globally/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down

0 comments on commit 6557dcf

Please sign in to comment.