Update to version 10.6.5: 1 New Feature And Indonesia Translation | Read HISTORY.md

Former-commit-id: 4788e36e52f6b40c7e15120e0675c097eabf0f0d
This commit is contained in:
Gerasimos Maropoulos 2018-05-21 07:40:43 +03:00
parent 8c41968905
commit 94b93484b5
19 changed files with 503 additions and 30 deletions

View File

@ -1,4 +1,4 @@
# History/Changelog <a href="HISTORY_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="HISTORY_GR.md"> <img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
# History/Changelog <a href="HISTORY_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a><a href="HISTORY_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a><a href="HISTORY_GR.md"> <img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
### Looking for free and real-time support?
@ -17,6 +17,103 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you.
# Mo, 21 May 2018 | v10.6.5
First of all, special thanks to [@haritsfahreza](https://github.com/haritsfahreza) for translating the entire Iris' README page & Changelogs to the Bahasa Indonesia language via PR: [#1000](https://github.com/kataras/iris/pull/1000)!
## New Feature: `Execution Rules`
From the begin of the Iris' journey we used to use the `ctx.Next()` inside handlers in order to call the next handler in the route's registered handlers chain, otherwise the "next handler" would never be executed.
We could always "force-break" that handlers chain using the `ctx.StopExecution()` to indicate that any future `ctx.Next()` calls will do nothing.
These things will never change, they were designed in the lower possible level of the Iris' high-performant and unique router and they're working like a charm:)
We have introduced `Iris MVC Applications` two years later. Iris is the first and the only one Go web framework with a realistic point-view and feature-rich MVC architectural pattern support without sacrifices, always with speed in mind (handlers vs mvc have almost the same speed here!!!).
A bit later we introduced another two unique features, `Hero Handlers and Service/Dynamic Bindings` (see the very bottom of this HISTORY page).
You loved it, you're using it a lot, just take a look at the recent github issues the community raised about MVC and etc.
Two recent discussions/support were about calling `Done` handlers inside MVC applications, you could simply do that by implementing the optional `BaseController` as examples shown, i.e:
```go
func (c *myController) BeginRequest(ctx iris.Context) {}
func (c *myController) EndRequest(ctx iris.Context) {
ctx.Next() // Call of any `Done` handlers.
}
```
But for some reason you found that confused. This is where the new feature comes: **The option to change the default behavior of handlers execution's rules PER PARTY**.
For example, we want to run all handlers(begin, main and done handlers) with the order you register but without the need of the `ctx.Next()` (in that case the only remained way to stop the lifecycle of an http request when next handlers are registered is to use the `ctx.StopExecution()` which, does not allow the next handler(s) to be executed even if `ctx.Next()` called in some place later on, but you're already know this, I hope :)).
```go
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/mvc"
)
func main() {
app := iris.New()
app.Get("/", func(ctx iris.Context) { ctx.Redirect("/example") })
m := mvc.New(app.Party("/example"))
// IMPORTANT
// the new feature, all options can be filled with Force:true, they are 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(...)
// ...
//
m.Handle(&exampleController{})
app.Run(iris.Addr(":8080"))
}
func doneHandler(ctx iris.Context) {
ctx.WriteString("\nFrom Done Handler")
}
type exampleController struct{}
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`.
//
// Therefore, the final output is:
// From Main Handler
// From Done Handler
}
```
Example at: [_examples/mvc/middleware/without-ctx-next](_examples/mvc/middleware/without-ctx-next).
This feature can be applied to any type of application, the example is an MVC Application because many of you asked for this exactly flow the past days.
## Thank you
Thank you for your honest support once again, your posts are the heart of this framework.
Don't forget to [star](https://github.com/kataras/iris/stargazers) the Iris' github repository whenever you can and spread the world about its potentials!
Be part of this,
- complete our User Experience Report: https://goo.gl/forms/lnRbVgA6ICTkPyk02
- join to our Community live chat: https://kataras.rocket.chat/channel/iris
- connect to our [new facebook group](https://www.facebook.com/iris.framework) to get notifications about new job opportunities relatively to Iris!
Sincerely,
[Gerasimos Maropoulos](https://twitter.com/MakisMaropoulos).
# We, 09 May 2018 | v10.6.4

View File

@ -1,4 +1,4 @@
# Ιστορικό <a href="HISTORY.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="HISTORY_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a>
# Ιστορικό <a href="HISTORY.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="HISTORY_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="HISTORY_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a>
### Ψάχνετε για δωρεάν υποστήριξη σε πραγματικό χρόνο;
@ -17,6 +17,10 @@
**Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `go get -u github.com/kataras/iris` ή αφήστε το αυτόματο updater να το κάνει αυτό για σας.
# Mo, 21 May 2018 | v10.6.5
This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#mo-21-may-2018--v1065) instead.
# We, 09 May 2018 | v10.6.4
- [διόρθωση του bug #995](https://github.com/kataras/iris/commit/62457279f41a1f157869a19ef35fb5198694fddb)

View File

@ -17,6 +17,9 @@ Developers tidak diwajibkan untuk melakukan upgrade apabila mereka tidak membutu
**Cara Upgrade**: Bukan command-line anda dan eksekuis perintah ini: `go get -u github.com/kataras/iris` atau biarkan updater otomatis melakukannya untuk anda.
# Mo, 21 May 2018 | v10.6.5
This history entry is not translated yet to the Bahasa Indonesia language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#mo-21-may-2018--v1065) instead.
# We, 09 May 2018 | v10.6.4

View File

@ -1,4 +1,4 @@
# 更新记录 <a href="HISTORY.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="HISTORY_GR.md"> <img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
# 更新记录 <a href="HISTORY.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="HISTORY_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="HISTORY_GR.md"> <img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
### 想得到免费即时的支持?
@ -17,6 +17,9 @@
**如何升级**: 打开命令行执行以下命令: `go get -u github.com/kataras/iris` 或者等待自动更新。
# Mo, 21 May 2018 | v10.6.5
This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#mo-21-may-2018--v1065) instead.
# We, 09 May 2018 | v10.6.4

View File

@ -1,4 +1,4 @@
# Iris Web Framework <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
# Iris Web Framework <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
@ -106,7 +106,7 @@ _Updated at: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_
## Support
- [HISTORY](HISTORY.md#we-09-may-2018--v1064) file is your best friend, it contains information about the latest features and changes
- [HISTORY](HISTORY.md#mo-21-may-2018--v1065) file is your best friend, it contains information about the latest features and changes
- Did you happen to find a bug? Post it at [github issues](https://github.com/kataras/iris/issues)
- Do you have any questions or need to speak with someone experienced to solve a problem at real-time? Join us to the [community chat](https://chat.iris-go.com)
- Complete our form-based user experience report by clicking [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)

View File

@ -1,4 +1,4 @@
# Iris Web Framework <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a>
# Iris Web Framework <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a>
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
@ -108,7 +108,7 @@ _Η τελευταία ενημέρωση έγινε την [Τρίτη, 21 Νο
## Υποστήριξη
- To [HISTORY](HISTORY_GR.md#we-09-may-2018--v1064) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές
- To [HISTORY](HISTORY_GR.md#mo-21-may-2018--v1065) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές
- Μήπως τυχαίνει να βρήκατε κάποιο bug; Δημοσιεύστε το στα [github issues](https://github.com/kataras/iris/issues)
- Έχετε οποιεσδήποτε ερωτήσεις ή πρέπει να μιλήσετε με κάποιον έμπειρο για την επίλυση ενός προβλήματος σε πραγματικό χρόνο; Ελάτε μαζί μας στην [συνομιλία κοινότητας](https://chat.iris-go.com)
- Συμπληρώστε την αναφορά εμπειρίας χρήστη κάνοντας κλικ [εδώ](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)

View File

@ -106,7 +106,7 @@ _Diperbarui pada: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_
## Dukungan
- File [HISTORY](HISTORY.md#we-09-may-2018--v1064) adalah sahabat anda, file tersebut memiliki informasi terkait fitur dan perubahan terbaru
- File [HISTORY](HISTORY_ID.md#mo-21-may-2018--v1065) adalah sahabat anda, file tersebut memiliki informasi terkait fitur dan perubahan terbaru
- Apakah anda menemukan bug? Laporkan itu melalui [github issues](https://github.com/kataras/iris/issues)
- Apakah anda memiliki pertanyaan atau butuh untuk bicara kepada seseorang yang sudah berpengalaman untuk menyelesaikan masalah secara langsung? Gabung bersama kami di [community chat](https://chat.iris-go.com)
- Lengkapi laporan user-experience berbasis formulir kami dengan tekan [disini](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)

View File

@ -1,4 +1,4 @@
# Iris Web Framework <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_ZH.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
# Iris Web Framework <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_ZH.md"><img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
@ -106,7 +106,7 @@ _Обновлено: [Вторник, 21 ноября 2017 г.](_benchmarks/READ
## Поддержка
- Файл [HISTORY](HISTORY.md#we-09-may-2018--v1064) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях
- Файл [HISTORY](HISTORY_RU.md#mo-21-may-2018--v1065) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях
- Вы случайно обнаружили ошибку? Опубликуйте ее на [Github вопросы](https://github.com/kataras/iris/issues)
- У Вас есть какие-либо вопросы или Вам нужно поговорить с кем-то, кто бы смог решить Вашу проблему в режиме реального времени? Присоединяйтесь к нам в [чате сообщества](https://chat.iris-go.com)
- Заполните наш отчет о пользовательском опыте на основе формы, нажав [здесь](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)

View File

@ -1,4 +1,4 @@
# Iris Web Framework <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
# Iris Web Framework <a href="README.md"> <img width="20px" src="https://iris-go.com/images/flag-unitedkingdom.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a>
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
@ -102,7 +102,7 @@ _更新于: [2017年11月21日星期二](_benchmarks/README_UNIX.md)_
## 支持
- [更新记录](HISTORY_ZH.md#we-09-may-2018--v1064) 是您最好的朋友,它包含有关最新功能和更改的信息
- [更新记录](HISTORY_ZH.md#mo-21-may-2018--v1065) 是您最好的朋友,它包含有关最新功能和更改的信息
- 你碰巧找到了一个错误? 请提交 [github issues](https://github.com/kataras/iris/issues)
- 您是否有任何疑问或需要与有经验的人士交谈以实时解决问题? [加入我们的聊天](https://chat.iris-go.com)
- [点击这里完成我们基于表单的用户体验报告](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)

View File

@ -1 +1 @@
10.6.4:https://github.com/kataras/iris/blob/master/HISTORY.md#we-09-may-2018--v1064
10.6.5:https://github.com/kataras/iris/blob/master/HISTORY.md#mo-21-may-2018--v1065

View File

@ -8,10 +8,10 @@ func main() {
app := iris.New()
// This will serve the ./static/favicons/favicon.ico to: localhost:8080/favicon.ico
app.Favicon("./static/favicons/favicon.ico.ico")
app.Favicon("./static/favicons/favicon.ico")
// app.Favicon("./static/favicons/favicon.ico.ico", "/favicon_16_16.ico")
// This will serve the ./static/favicons/favicon.ico.ico to: localhost:8080/favicon_16_16.ico
// app.Favicon("./static/favicons/favicon.\\.ico", "/favicon_16_16.ico")
// This will serve the ./static/favicons/favicon.ico to: localhost:8080/favicon_16_16.ico
app.Get("/", func(ctx iris.Context) {
ctx.HTML(`<a href="/favicon.ico"> press here to see the favicon.ico</a>.

View File

@ -0,0 +1,72 @@
/*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.
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`
to be executed but we don't want to add `ctx.Next()` on the `exampleController#EndRequest`*/
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/mvc"
)
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"))
// 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(...)
// ...
//
m.Handle(&exampleController{})
app.Run(iris.Addr(":8080"))
}
func doneHandler(ctx iris.Context) {
ctx.WriteString("\nFrom Done Handler")
}
type exampleController struct{}
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`.
//
// Therefore the final output is:
// From Main Handler
// From Done Handler
}

View File

@ -13,7 +13,7 @@ import (
const (
// Version is the string representation of the current local Iris Web Framework version.
Version = "10.6.4"
Version = "10.6.5"
)
// CheckForUpdates checks for any available updates

View File

@ -94,8 +94,9 @@ type APIBuilder struct {
// the per-party done handlers, order matters.
doneHandlers context.Handlers
// global done handlers, order doesn't matter
// global done handlers, order doesn't matter.
doneGlobalHandlers context.Handlers
// the per-party
relativePath string
// allowMethods are filled with the `AllowMethods` func.
@ -103,6 +104,9 @@ type APIBuilder struct {
// per any party's (and its children) routes registered
// if the method "x" wasn't registered already via the `Handle` (and its extensions like `Get`, `Post`...).
allowMethods []string
// the per-party (and its children) execution rules for begin, main and done handlers.
handlerExecutionRules ExecutionRules
}
var _ Party = (*APIBuilder)(nil)
@ -150,6 +154,34 @@ func (api *APIBuilder) AllowMethods(methods ...string) Party {
return api
}
// 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`
// to be executed but we don't want to add `ctx.Next()` on the `OurController#EndRequest`.
//
// Returns this Party.
//
// Example: https://github.com/kataras/iris/tree/master/_examples/mvc/middleware/without-ctx-next
func (api *APIBuilder) SetExecutionRules(executionRules ExecutionRules) Party {
api.handlerExecutionRules = executionRules
return api
}
// Handle registers a route to the server's api.
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
//
@ -179,14 +211,28 @@ func (api *APIBuilder) Handle(method string, relativePath string, handlers ...co
return nil
}
// before join the middleware + handlers + done handlers.
possibleMainHandlerName := context.HandlerName(handlers[0])
// note: this can not change the caller's handlers as they're but the entry values(handlers)
// of `middleware`, `doneHandlers` and `handlers` can.
// So if we just put `api.middleware` or `api.doneHandlers`
// then the next `Party` will have those updated handlers
// but dev may change the rules for that child Party, so we have to make clones of them here.
var (
beginHandlers = joinHandlers(api.middleware, context.Handlers{})
doneHandlers = joinHandlers(api.doneHandlers, context.Handlers{})
)
mainHandlers := context.Handlers(handlers)
// before join the middleware + handlers + done handlers and apply the execution rules.
possibleMainHandlerName := context.HandlerName(mainHandlers[0])
// TODO: for UseGlobal/DoneGlobal that doesn't work.
applyExecutionRules(api.handlerExecutionRules, &beginHandlers, &doneHandlers, &mainHandlers)
// global begin handlers -> middleware that are registered before route registration
// -> handlers that are passed to this Handle function.
routeHandlers := joinHandlers(api.middleware, handlers)
routeHandlers := joinHandlers(beginHandlers, mainHandlers)
// -> done handlers
routeHandlers = joinHandlers(routeHandlers, api.doneHandlers)
routeHandlers = joinHandlers(routeHandlers, doneHandlers)
// here we separate the subdomain and relative path
subdomain, path := splitSubdomainAndPath(fullpath)
@ -304,6 +350,7 @@ func (api *APIBuilder) Party(relativePath string, handlers ...context.Handler) P
doneHandlers: api.doneHandlers[0:],
relativePath: fullpath,
allowMethods: allowMethods,
handlerExecutionRules: api.handlerExecutionRules,
}
}
@ -456,12 +503,14 @@ func (api *APIBuilder) DoneGlobal(handlers ...context.Handler) {
}
// Reset removes all the begin and done handlers that may derived from the parent party via `Use` & `Done`,
// note that the `Reset` will not reset the handlers that are registered via `UseGlobal` & `DoneGlobal`.
// and the execution rules.
// Note that the `Reset` will not reset the handlers that are registered via `UseGlobal` & `DoneGlobal`.
//
// Returns this Party.
func (api *APIBuilder) Reset() Party {
api.middleware = api.middleware[0:0]
api.doneHandlers = api.doneHandlers[0:0]
api.handlerExecutionRules = ExecutionRules{}
return api
}

View File

@ -0,0 +1,115 @@
package router
import (
"github.com/kataras/iris/context"
)
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
// Usage:
// Party#SetExecutionRules(ExecutionRules {
// Done: ExecutionOptions{Force: true},
// })
//
// See `Party#SetExecutionRules` for more.
type ExecutionRules struct {
// Begin applies from `Party#Use`/`APIBUilder#UseGlobal` to the first...!last `Party#Handle`'s IF main handlers > 1.
Begin ExecutionOptions
// Done applies to the latest `Party#Handle`'s (even if one) and all done handlers.
Done ExecutionOptions
// Main applies to the `Party#Handle`'s all handlers, plays nice with the `Done` rule
// when more than one handler was registered in `Party#Handle` without `ctx.Next()` (for Force: true).
Main ExecutionOptions
}
func handlersNames(handlers context.Handlers) (names []string) {
for _, h := range handlers {
if h == nil {
continue
}
names = append(names, context.HandlerName(h))
}
return
}
func applyExecutionRules(rules ExecutionRules, begin, done, main *context.Handlers) {
if !rules.Begin.Force && !rules.Done.Force && !rules.Main.Force {
return // do not proceed and spend buld-time here if nothing changed.
}
beginOK := rules.Begin.apply(begin)
mainOK := rules.Main.apply(main)
doneOK := rules.Done.apply(done)
if !mainOK {
mainCp := (*main)[0:]
lastIdx := len(mainCp) - 1
if beginOK {
if len(mainCp) > 1 {
mainCpFirstButNotLast := make(context.Handlers, lastIdx)
copy(mainCpFirstButNotLast, mainCp[:lastIdx])
for i, h := range mainCpFirstButNotLast {
(*main)[i] = rules.Begin.buildHandler(h)
}
}
}
if doneOK {
latestMainHandler := mainCp[lastIdx]
(*main)[lastIdx] = rules.Done.buildHandler(latestMainHandler)
}
}
}
// ExecutionOptions is a set of default behaviors that can be changed in order to customize the execution flow of the routes' handlers with ease.
//
// See `ExecutionRules` and `Party#SetExecutionRules` for more.
type ExecutionOptions struct {
// Force if true then the handler9s) will execute even if the previous (or/and current, depends on the type of the rule)
// handler does not calling the `ctx.Next()`,
// note that the only way remained to stop a next handler is with the `ctx.StopExecution()` if this option is true.
//
// If true and `ctx.Next()` exists in the handlers that it shouldn't be, the framework will understand it but use it wisely.
//
// Defaults to false.
Force bool
}
func (e ExecutionOptions) buildHandler(h context.Handler) context.Handler {
if !e.Force {
return h
}
return func(ctx context.Context) {
// Proceed will fire the handler and return false here if it doesn't contain a `ctx.Next()`,
// so we add the `ctx.Next()` wherever is necessary in order to eliminate any dev's misuse.
if !ctx.Proceed(h) {
// `ctx.Next()` always checks for `ctx.IsStopped()` and handler(s) positions by-design.
ctx.Next()
}
}
}
func (e ExecutionOptions) apply(handlers *context.Handlers) bool {
if !e.Force {
return false
}
tmp := *handlers
for i, h := range tmp {
if h == nil {
if len(tmp) == 1 {
return false
}
continue
}
(*handlers)[i] = e.buildHandler(h)
}
return true
}

View File

@ -0,0 +1,91 @@
package router_test
import (
"testing"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/core/router"
"github.com/kataras/iris/httptest"
)
var (
finalExecutionRulesResponse = "1234"
testExecutionResponse = func(t *testing.T, app *iris.Application, path string) {
e := httptest.New(t, app)
e.GET(path).Expect().Status(httptest.StatusOK).Body().Equal(finalExecutionRulesResponse)
}
)
func writeStringHandler(text string, withNext bool) context.Handler {
return func(ctx context.Context) {
ctx.WriteString(text)
if withNext {
ctx.Next()
}
}
}
func TestRouterExecutionRulesForceMain(t *testing.T) {
app := iris.New()
begin := app.Party("/")
begin.SetExecutionRules(router.ExecutionRules{Main: router.ExecutionOptions{Force: true}})
// no need of `ctx.Next()` all main handlers should be executed with the Main.Force:True rule.
begin.Get("/", writeStringHandler("12", false), writeStringHandler("3", false), writeStringHandler("4", false))
testExecutionResponse(t, app, "/")
}
func TestRouterExecutionRulesForceBegin(t *testing.T) {
app := iris.New()
begin := app.Party("/begin_force")
begin.SetExecutionRules(router.ExecutionRules{Begin: router.ExecutionOptions{Force: true}})
// should execute, begin rule is to force execute them without `ctx.Next()`.
begin.Use(writeStringHandler("1", false))
begin.Use(writeStringHandler("2", false))
// begin starts with begin and ends to the main handlers but not last, so this done should not be executed.
begin.Done(writeStringHandler("5", false))
begin.Get("/", writeStringHandler("3", false), writeStringHandler("4", false))
testExecutionResponse(t, app, "/begin_force")
}
func TestRouterExecutionRulesForceDone(t *testing.T) {
app := iris.New()
done := app.Party("/done_force")
done.SetExecutionRules(router.ExecutionRules{Done: router.ExecutionOptions{Force: true}})
// these done should be executed without `ctx.Next()`
done.Done(writeStringHandler("3", false), writeStringHandler("4", false))
// first with `ctx.Next()`, because Done.Force:True rule will alter the latest of the main handler(s) only.
done.Get("/", writeStringHandler("1", true), writeStringHandler("2", false))
// rules should be kept in children.
doneChild := done.Party("/child")
// even if only one, it's the latest, Done.Force:True rule should modify it.
doneChild.Get("/", writeStringHandler("12", false))
testExecutionResponse(t, app, "/done_force")
testExecutionResponse(t, app, "/done_force/child")
}
func TestRouterExecutionRulesShouldNotModifyTheCallersHandlerAndChildrenCanResetExecutionRules(t *testing.T) {
app := iris.New()
app.SetExecutionRules(router.ExecutionRules{Done: router.ExecutionOptions{Force: true}})
h := writeStringHandler("4", false)
app.Done(h)
app.Get("/", writeStringHandler("123", false))
// remember: the handler stored in var didn't had a `ctx.Next()`, modified its clone above with adding a `ctx.Next()`
// note the "clone" word, the original handler shouldn't be changed.
app.Party("/c").SetExecutionRules(router.ExecutionRules{}).Get("/", h, writeStringHandler("err caller modified!", false))
testExecutionResponse(t, app, "/")
e := httptest.New(t, app)
e.GET("/c").Expect().Status(httptest.StatusOK).Body().Equal("4") // the "should not" should not be written.
}

View File

@ -61,7 +61,8 @@ type Party interface {
// The difference from .Use is that this/or these Handler(s) are being always running last.
Done(handlers ...context.Handler)
// Reset removes all the begin and done handlers that may derived from the parent party via `Use` & `Done`,
// note that the `Reset` will not reset the handlers that are registered via `UseGlobal` & `DoneGlobal`.
// and the execution rules.
// Note that the `Reset` will not reset the handlers that are registered via `UseGlobal` & `DoneGlobal`.
//
// Returns this Party.
Reset() Party
@ -73,6 +74,30 @@ type Party interface {
// Call of `AllowMethod` will override any previous allow methods.
AllowMethods(methods ...string) 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`
// to be executed but we don't want to add `ctx.Next()` on the `OurController#EndRequest`.
//
// Returns this Party.
//
// Example: https://github.com/kataras/iris/tree/master/_examples/mvc/middleware/without-ctx-next
SetExecutionRules(executionRules ExecutionRules) Party
// Handle registers a route to the server's router.
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
//

2
doc.go
View File

@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub:
Current Version
10.6.4
10.6.5
Installation

14
go19.go
View File

@ -57,4 +57,18 @@ type (
//
// A shortcut for the `core/router#Party`, useful when `PartyFunc` is being used.
Party = router.Party
// ExecutionRules gives control to the execution of the route handlers outside of the handlers themselves.
// Usage:
// Party#SetExecutionRules(ExecutionRules {
// Done: ExecutionOptions{Force: true},
// })
//
// See `core/router/Party#SetExecutionRules` for more.
// Example: https://github.com/kataras/iris/tree/master/_examples/mvc/middleware/without-ctx-next
ExecutionRules = router.ExecutionRules
// ExecutionOptions is a set of default behaviors that can be changed in order to customize the execution flow of the routes' handlers with ease.
//
// See `ExecutionRules` and `core/router/Party#SetExecutionRules` for more.
ExecutionOptions = router.ExecutionOptions
)