mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
Update to version 10.6.5: 1 New Feature And Indonesia Translation | Read HISTORY.md
Former-commit-id: 4788e36e52f6b40c7e15120e0675c097eabf0f0d
This commit is contained in:
parent
8c41968905
commit
94b93484b5
99
HISTORY.md
99
HISTORY.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -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
|
|
@ -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>.
|
||||
|
|
72
_examples/mvc/middleware/without-ctx-next/main.go
Normal file
72
_examples/mvc/middleware/without-ctx-next/main.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
115
core/router/handler_execution_rules.go
Normal file
115
core/router/handler_execution_rules.go
Normal 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
|
||||
}
|
91
core/router/handler_execution_rules_test.go
Normal file
91
core/router/handler_execution_rules_test.go
Normal 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.
|
||||
}
|
|
@ -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
2
doc.go
|
@ -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
14
go19.go
|
@ -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
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user