Latest release

v10.0.2

@kataras kataras released this Jan 16, 2018 · 11 commits to master since this release

History/Changelog

Tu, 16 Jenuary 2018 | v10.0.2

Security | iris.AutoTLS

Every server should be upgraded to this version, it contains fixes for the tls-sni challenge disabled some days ago by letsencrypt.org which caused almost every https-enabled golang server to be unable to be functional, therefore support for the http-01 challenge type added. Now the server is testing all available letsencrypt challenges.

Read more at:

Mo, 15 Jenuary 2018 | v10.0.1

Not any serious problems were found to be resolved here but one, the first one which is important for devs that used the cache package.

  • fix a single one cache handler didn't work across multiple route handlers at the same time #852, as reported at #850
  • merge PR #862
  • do not allow concurrent access to the ExecuteWriter -> Load when view#Engine##Reload was true, as requested at #872
  • badge for open-source projects powered by Iris, learn how to add that badge to your open-source project at FAQ.md file
  • upstream update for golang/crypto to apply the fix about the tls-sni challenge disabled golang/crypto@13931e2 (relative to iris.AutoTLS)

New Backers

  1. https://opencollective.com/cetin-basoz

New Translations

  1. The Chinese README_ZH.md and HISTORY_ZH.md was translated by @Zeno-Code via #858
  2. New Russian README_RU.md translations by @merrydii via #857
  3. New Greek README_GR.md and HISTORY_GR.md translations via 8c4e17c#diff-74b06c740d860f847e7b577ad58ddde0 and bb5a81c

New Examples

  1. MVC - Register Middleware

New Articles

  1. A Todo MVC Application using Iris and Vue.js
  2. A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS

Mo, 01 Jenuary 2018 | v10.0.0

We must thanks Mrs. Diana for our awesome new logo!

You can contact her for any design-related enquiries or explore and send a direct message via instagram.

At this version we have many internal improvements but just two major changes and one big feature, called hero.

The new version adds 75 plus new commits, the PR is located here read the internal changes if you are developing a web framework based on Iris. Why 9 was skipped? Because.

Hero

The new package hero contains features for binding any object or function that handlers may use, these are called dependencies. Hero funcs can also return any type of values, these values will be dispatched to the client.

You may saw binding before but you didn't have code editor's support, with Iris you get truly safe binding thanks to the new hero package. It's also fast, near to raw handlers performance because Iris calculates everything before server ran!

Below you will see some screenshots we prepared for you in order to be easier to understand:

1. Path Parameters - Built'n Dependencies

2. Services - Static Dependencies

3. Per-Request - Dynamic Dependencies

hero funcs are very easy to understand and when you start using them you never go back.

Examples:

MVC

You have to understand the hero package in order to use the mvc, because mvc uses the hero internally for the controller's methods you use as routes, the same rules applied to those controller's methods of yours as well.

With this version you can register any controller's methods as routes manually, you can get a route based on a method name and change its Name (useful for reverse routing inside templates), you can use any dependencies registered from hero.Register or mvc.New(iris.Party).Register per mvc application or per-controller, you can still use BeginRequest and EndRequest, you can catch BeforeActivation(b mvc.BeforeActivation) to add dependencies per controller and AfterActivation(a mvc.AfterActivation) to make any post-validations, singleton controllers when no dynamic dependencies are used, Websocket controller, as simple as a websocket.Connection dependency and more...

Examples:

If you used MVC before then read very carefully: MVC CONTAINS SOME BREAKING CHANGES BUT YOU CAN DO A LOT MORE AND EVEN FASTER THAN BEFORE

PLEASE READ THE EXAMPLES CAREFULLY, WE'VE MADE THEM FOR YOU

Old examples are here as well. Compare the two different versions of each example to understand what you win if you upgrade now.

NEW OLD
Hello world OLD Hello world
Session Controller OLD Session Controller
Overview - Plus Repository and Service layers OLD Overview - Plus Repository and Service layers
Login showcase - Plus Repository and Service layers OLD Login showcase - Plus Repository and Service layers
Singleton NEW
Websocket Controller NEW
Vue.js Todo MVC NEW

context#PostMaxMemory

Remove the old static variable context.DefaultMaxMemory and replace it with the configuration WithPostMaxMemory.

// WithPostMaxMemory sets the maximum post data size
// that a client can send to the server, this differs
// from the overral request body size which can be modified
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
//
// Defaults to 32MB or 32 << 20 if you prefer.
func WithPostMaxMemory(limit int64) Configurator

If you used that old static field you will have to change that single line.

Usage:

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    // [...]

    app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20))
}

context#UploadFormFiles

New method to upload multiple files, should be used for common upload actions, it's just a helper function.

// UploadFormFiles uploads any received file(s) from the client
// to the system physical location "destDirectory".
//
// The second optional argument "before" gives caller the chance to
// modify the *miltipart.FileHeader before saving to the disk,
// it can be used to change a file's name based on the current request,
// all FileHeader's options can be changed. You can ignore it if
// you don't need to use this capability before saving a file to the disk.
//
// Note that it doesn't check if request body streamed.
//
// Returns the copied length as int64 and
// a not nil error if at least one new file
// can't be created due to the operating system's permissions or
// http.ErrMissingFile if no file received.
//
// If you want to receive & accept files and manage them manually you can use the `context#FormFile`
// instead and create a copy function that suits your needs, the below is for generic usage.
//
// The default form's memory maximum size is 32MB, it can be changed by the
//  `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
//
// See `FormFile` to a more controlled to receive a file.
func (ctx *context) UploadFormFiles(
        destDirectory string,
        before ...func(string, string),
    ) (int64, error)

Example can be found here.

context#View

Just a minor addition, add a second optional variadic argument to the context#View method to accept a single value for template binding.
When you just want one value and not key-value pairs, you used to use an empty string on the ViewData, which is fine, especially if you preload these from a previous handler/middleware in the request handlers chain.

func(ctx iris.Context) {
    ctx.ViewData("", myItem{Name: "iris" })
    ctx.View("item.html")
}

Same as:

func(ctx iris.Context) {
    ctx.View("item.html", myItem{Name: "iris" })
}
Item's name: {{.Name}}

context#YAML

Add a new context#YAML function, it renders a yaml from a structured value.

// YAML marshals the "v" using the yaml marshaler and renders its result to the client.
func YAML(v interface{}) (int, error)

Session#GetString

sessions/session#GetString can now return a filled value even if the stored value is a type of integer, just like the memstore, the context's temp store, the context's path parameters and the context's url parameters.

v10.0.1

@kataras kataras released this Jan 15, 2018 · 15 commits to master since this release

Mo, 15 Jenuary 2018 | v10.0.1

Not any serious problems were found to be resolved here but one, the first one which is important for devs that used the cache package.

  • fix a single one cache handler didn't work across multiple route handlers at the same time #852, as reported at #850
  • merge PR #862
  • do not allow concurrent access to the ExecuteWriter -> Load when view#Engine##Reload was true, as requested at #872
  • badge for open-source projects powered by Iris, learn how to add that badge to your open-source project at FAQ.md file
  • upstream update for golang/crypto to apply the fix about the tls-sni challenge disabled golang/crypto@13931e2 (relative to iris.AutoTLS)

New Backers

  1. https://opencollective.com/cetin-basoz

New Translations

  1. The Chinese README_ZH.md and HISTORY_ZH.md was translated by @Zeno-Code via #858
  2. New Russian README_RU.md translations by @merrydii via #857
  3. New Greek README_GR.md and HISTORY_GR.md translations via 8c4e17c#diff-74b06c740d860f847e7b577ad58ddde0 and bb5a81c

New Examples

  1. MVC - Register Middleware

New Articles

  1. A Todo MVC Application using Iris and Vue.js
  2. A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS

Mo, 01 Jenuary 2018 | v10.0.0

We must thanks Mrs. Diana for our awesome new logo!

You can contact her for any design-related enquiries or explore and send a direct message via instagram.

At this version we have many internal improvements but just two major changes and one big feature, called hero.

The new version adds 75 plus new commits, the PR is located here read the internal changes if you are developing a web framework based on Iris. Why 9 was skipped? Because.

Hero

The new package hero contains features for binding any object or function that handlers may use, these are called dependencies. Hero funcs can also return any type of values, these values will be dispatched to the client.

You may saw binding before but you didn't have code editor's support, with Iris you get truly safe binding thanks to the new hero package. It's also fast, near to raw handlers performance because Iris calculates everything before server ran!

Below you will see some screenshots we prepared for you in order to be easier to understand:

1. Path Parameters - Built'n Dependencies

2. Services - Static Dependencies

3. Per-Request - Dynamic Dependencies

hero funcs are very easy to understand and when you start using them you never go back.

Examples:

MVC

You have to understand the hero package in order to use the mvc, because mvc uses the hero internally for the controller's methods you use as routes, the same rules applied to those controller's methods of yours as well.

With this version you can register any controller's methods as routes manually, you can get a route based on a method name and change its Name (useful for reverse routing inside templates), you can use any dependencies registered from hero.Register or mvc.New(iris.Party).Register per mvc application or per-controller, you can still use BeginRequest and EndRequest, you can catch BeforeActivation(b mvc.BeforeActivation) to add dependencies per controller and AfterActivation(a mvc.AfterActivation) to make any post-validations, singleton controllers when no dynamic dependencies are used, Websocket controller, as simple as a websocket.Connection dependency and more...

Examples:

If you used MVC before then read very carefully: MVC CONTAINS SOME BREAKING CHANGES BUT YOU CAN DO A LOT MORE AND EVEN FASTER THAN BEFORE

PLEASE READ THE EXAMPLES CAREFULLY, WE'VE MADE THEM FOR YOU

Old examples are here as well. Compare the two different versions of each example to understand what you win if you upgrade now.

NEW OLD
Hello world OLD Hello world
Session Controller OLD Session Controller
Overview - Plus Repository and Service layers OLD Overview - Plus Repository and Service layers
Login showcase - Plus Repository and Service layers OLD Login showcase - Plus Repository and Service layers
Singleton NEW
Websocket Controller NEW
Vue.js Todo MVC NEW

context#PostMaxMemory

Remove the old static variable context.DefaultMaxMemory and replace it with the configuration WithPostMaxMemory.

// WithPostMaxMemory sets the maximum post data size
// that a client can send to the server, this differs
// from the overral request body size which can be modified
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
//
// Defaults to 32MB or 32 << 20 if you prefer.
func WithPostMaxMemory(limit int64) Configurator

If you used that old static field you will have to change that single line.

Usage:

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    // [...]

    app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20))
}

context#UploadFormFiles

New method to upload multiple files, should be used for common upload actions, it's just a helper function.

// UploadFormFiles uploads any received file(s) from the client
// to the system physical location "destDirectory".
//
// The second optional argument "before" gives caller the chance to
// modify the *miltipart.FileHeader before saving to the disk,
// it can be used to change a file's name based on the current request,
// all FileHeader's options can be changed. You can ignore it if
// you don't need to use this capability before saving a file to the disk.
//
// Note that it doesn't check if request body streamed.
//
// Returns the copied length as int64 and
// a not nil error if at least one new file
// can't be created due to the operating system's permissions or
// http.ErrMissingFile if no file received.
//
// If you want to receive & accept files and manage them manually you can use the `context#FormFile`
// instead and create a copy function that suits your needs, the below is for generic usage.
//
// The default form's memory maximum size is 32MB, it can be changed by the
//  `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
//
// See `FormFile` to a more controlled to receive a file.
func (ctx *context) UploadFormFiles(
        destDirectory string,
        before ...func(string, string),
    ) (int64, error)

Example can be found here.

context#View

Just a minor addition, add a second optional variadic argument to the context#View method to accept a single value for template binding.
When you just want one value and not key-value pairs, you used to use an empty string on the ViewData, which is fine, especially if you preload these from a previous handler/middleware in the request handlers chain.

func(ctx iris.Context) {
    ctx.ViewData("", myItem{Name: "iris" })
    ctx.View("item.html")
}

Same as:

func(ctx iris.Context) {
    ctx.View("item.html", myItem{Name: "iris" })
}
Item's name: {{.Name}}

context#YAML

Add a new context#YAML function, it renders a yaml from a structured value.

// YAML marshals the "v" using the yaml marshaler and renders its result to the client.
func YAML(v interface{}) (int, error)

Session#GetString

sessions/session#GetString can now return a filled value even if the stored value is a type of integer, just like the memstore, the context's temp store, the context's path parameters and the context's url parameters.

Chinese

2018 1月15号 | v10.0.1 版本更新

该版本暂未发现重大问题,但如果你使用 cache 包的话,这里有些更新或许正好解决某些问题。

  • 修复缓存在同一控制器多个方法中,返回相同内容问题 #852, 问题报告:#850
  • 问题修正 #862
  • view#Engine##Reload 为 true,ExecuteWriter -> Load 不能同时使用问题,相关问题 :#872
  • 由Iris提供支持的开源项目的徽章, 学习如何将徽章添加到您的开源项目中 FAQ.md

新增捐助

  1. https://opencollective.com/cetin-basoz

新增翻译

  1. 中文版 README_ZH.md and HISTORY_ZH.md 由 @Zeno-Code 翻译 #858
  2. 俄语版 README_RU.md 由 @merrydii 翻译 #857
  3. 希腊版 README_GR.md and HISTORY_GR.md 8c4e17c#diff-74b06c740d860f847e7b577ad58ddde0 and bb5a81c

新增示例

  1. MVC - Register Middleware

新增文章

  1. A Todo MVC Application using Iris and Vue.js
  2. A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS

2018 元旦 | v10.0.0 版本发布

我们必须感谢 Mrs. Diana 帮我们绘制的漂亮 logo!

如果有设计相关的需求,你可以发邮件给他,或者通过 instagram 给他发信息。

在这个版本中,有许多内部优化改进,但只有两个重大变更和新增一个叫做 hero 的特性。

新版本有 75 + 的变更提交, 如果你需要升级 Iris 请仔细阅读本文档。 为什么版本 9 跳过了? 你猜...

Hero 特性

新增包 hero 可以绑定处理任何依赖 handlers 的对象或函数。Hero funcs 可以返回任何类型的值,并发送给客户端。

之前的绑定没有编辑器的支持, 新包 hero 为 Iris 带来真正的安全绑定。 Iris 会在服务器运行之前计算所有内容,所以它执行速度高,接近于原生性能。

下面你会看到我们为你准备的一些截图,以便于理解:

1. 路径参数 - 构建依赖

2. 服务 - 静态依赖

3. 请求之前 - 动态依赖

hero funcs 非常容易理解,当你用过之后 在也回不去了.

示例:

MVC

You have to understand the hero package in order to use the mvc, because mvc uses the hero internally for the controller's methods you use as routes, the same rules applied to those controller's methods of yours as well.

如果要使用 mvc ,必须先理解 hero 包,因为mvc在内部使用hero作为路由控制器的方法,同样的规则也适用于你的控制器的方法。

With this version you can register any controller's methods as routes manually, you can get a route based on a method name and change its Name (useful for reverse routing inside templates), you can use any dependencies registered from hero.Register or mvc.New(iris.Party).Register per mvc application or per-controller, you can still use BeginRequest and EndRequest, you can catch BeforeActivation(b mvc.BeforeActivation) to add dependencies per controller and AfterActivation(a mvc.AfterActivation) to make any post-validations, singleton controllers when no dynamic dependencies are used, Websocket controller, as simple as a websocket.Connection dependency and more...

示例:

如果你之前使用过 MVC ,请仔细阅读:MVC 包含一些破坏性的改进,但新的方式可以做更多,会让程序执行更快

请阅读我们为你准备的示例

如果你现在需要升级,请对比新旧版本示例的不同,便于理解。

NEW OLD
Hello world OLD Hello world
Session Controller OLD Session Controller
Overview - Plus Repository and Service layers OLD Overview - Plus Repository and Service layers
Login showcase - Plus Repository and Service layers OLD Login showcase - Plus Repository and Service layers
Singleton 新增
Websocket Controller 新增
Vue.js Todo MVC 新增

context#PostMaxMemory

移除旧版本的常量 context.DefaultMaxMemory 替换为配置 WithPostMaxMemory 方法.

// WithPostMaxMemory sets the maximum post data size
// that a client can send to the server, this differs
// from the overral request body size which can be modified
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
//
// 默认值为 32MB 或者 32 << 20
func WithPostMaxMemory(limit int64) Configurator

如果你使用老版本的常量,你需要更改一行代码.

使用方式:

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    // [...]

    app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20))
}

context#UploadFormFiles

新方法可以多文件上传, 应用于常见的上传操作, 它是一个非常有用的函数。

// UploadFormFiles uploads any received file(s) from the client
// to the system physical location "destDirectory".
//
// The second optional argument "before" gives caller the chance to
// modify the *miltipart.FileHeader before saving to the disk,
// it can be used to change a file's name based on the current request,
// all FileHeader's options can be changed. You can ignore it if
// you don't need to use this capability before saving a file to the disk.
//
// Note that it doesn't check if request body streamed.
//
// Returns the copied length as int64 and
// a not nil error if at least one new file
// can't be created due to the operating system's permissions or
// http.ErrMissingFile if no file received.
//
// If you want to receive & accept files and manage them manually you can use the `context#FormFile`
// instead and create a copy function that suits your needs, the below is for generic usage.
//
// The default form's memory maximum size is 32MB, it can be changed by the
//  `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
//
// See `FormFile` to a more controlled to receive a file.
func (ctx *context) UploadFormFiles(
        destDirectory string,
        before ...func(string, string),
    ) (int64, error)

这里是相关示例 here.

context#View

这里有个小更新,增加可选的第二个参数,用来绑定模版变量。提示:这种绑定方式,会忽略其他变量的绑定。
如果要忽略其他模版变量,之前是在 ViewData 上绑定一个空字符串,现在可以直接通过 View 方法添加。

func(ctx iris.Context) {
    ctx.ViewData("", myItem{Name: "iris" })
    ctx.View("item.html")
}

等同于:

func(ctx iris.Context) {
    ctx.View("item.html", myItem{Name: "iris" })
}
html 模版中调用: {{.Name}}

context#YAML

新增 context#YAML 函数, 解析结构体到 yaml。

//使用 yaml 包的 Marshal 的方法解析,并发送到客户端。
func YAML(v interface{}) (int, error)

Session#GetString

sessions/session#GetString 可以获取 session 的变量值(可以是 integer 类型),就像内存缓存、Context 上下文储存的值。

Greek

Mo, 15 Jenuary 2018 | v10.0.1

  • διόρθωση του cache handler που δεν δούλευε όπως έπρεπε όταν γινόταν εγγραφή σε πάνω από ένα handler, παλιότερα ήταν ένα cache handler προς ένα route handler, τώρα το ίδιο handler μπορεί να καταχωρηθεί σε όσα route handlers θέλετε #852, όπως είχε αναφερθεί στο #850
  • συγχώνευση PR #862
  • απαγόρευση της ταυτόχρονης προσπέλασης του ExecuteWriter -> Load όταν το view#Engine##Reload είναι true, όπως είχε ζητηθεί στο #872
  • αναβάθμιση του ενσωματωμένου πακέτου golang/crypto για να εφαρμοστεί η επιδιόρθωση για το tls-sni challenge disabled golang/crypto@13931e2 (σχετικό με το iris.AutoTLS)

Νέοι Υποστηρικτές

  1. https://opencollective.com/cetin-basoz

Νέες Μεταφράσεις

  1. Aναβαθμίσεις για την Κινέζικη μετάφραση README_ZH.md (νέο) και HISTORY_ZH.md από @Zeno-Code μέσω του #858
  2. Το Ρώσικο README_RU.md μεταφράστηκε από την @merrydii μέσω του #857
  3. Τα Ελληνικά README_GR.md και HISTORY_GR.md μεταφράστηκαν μέσω των 8c4e17c#diff-74b06c740d860f847e7b577ad58ddde0 και bb5a81c

Νέα Παραδείγματα

  1. MVC - Register Middleware

Νέα Άρθρα

  1. A Todo MVC Application using Iris and Vue.js
  2. A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS

Mo, 01 Jenuary 2018 | v10.0.0

Πρέπει να ευχαριστήσουμε την Κυρία Diana για το νέο μας λογότυπο!

Μπορείτε να επικοινωνήσετε μαζί της για οποιεσδήποτε σχετικές με το σχεδιασμό εργασίες ή να της στείλειτε ένα άμεσο μήνυμα μέσω instagram.

Σε αυτή την έκδοση έχουμε πολλές εσωτερικές βελτιώσεις αλλά μόνο δύο μεγάλες αλλαγές και ένα μεγάλο χαρακτηριστικό, που ονομάζεται hero.

Η νέα έκδοση προσθέτει 75 καινούρια commits, το PR βρίσκεται εδώ. Παρακαλώ διαβάστε τις εσωτερικές αλλαγές αν σχεδιάζετε ένα web framework που βασίζεται στο Iris. Γιατί η έκδοση 9 παραλείφθηκε; Έτσι.

Hero

Το νέο πακέτο hero περιέχει χαρακτηριστικά για σύνδεση(binding) οποιουδήποτε αντικειμένου ή function το οποίο τα handlers μπορεί να χρησημοποιούν, αυτά λεγόνται εξαρτήσεις(dependencies). Τα Hero funcs μπορούν επίσης να επιστρέψουν οποιαδήποτε τιμή, οποιουδήποτε τύπου, αυτές οι τιμές αποστέλλονται στον πελάτη(client).

Μπορεί να είχατε ξαναδει "εξαρτήσεις" και "δέσιμο" πριν αλλά ποτέ με υποστήριξη από τον επεξεργαστή κώδικα (code editor), με το Iris πέρνεις πραγματικά ασφαλή "δεσίματα"(bindings) χάρη στο νέο hero πακέτο. Αυτή η όλη εκτέλεση(implementation) είναι επίσης η ποιο γρήγορη που έχει επιτευχθεί εως τώρα, η επίδοση είναι πολύ κοντά στα απλά "handlers" και αυτό γιατί το Iris υπολογίζει τα πάντα πριν καν ο server τρέξει!

Παρακάτω θα δείτε μερικά στιγμιότυπα που ετοιμάσαμε για εσάς, ώστε να γίνουν πιο κατανοητά τα παραπάνω:

1. Παράμετροι διαδρομής - Ενσωματωμένες Εξαρτήσεις (Built'n Dependencies)

2. Υπηρεσίες - Στατικές Eξαρτήσεις (Static Dependencies)

3. Ανά Αίτηση - Δυναμικές Eξαρτήσεις (Dynamic Dependencies)

Είναι πραγματικά πολύ εύκολο να καταλάβεις πως δουλεύουν τα hero funcs και όταν αρχίσεις να τα χρησιμοποιείς δεν γυρίζεις ποτέ πίσω.

Παραδείγματα:

MVC

Πρέπει να καταλάβεις πως δουλεύει το hero πακετό ώστε να να δουλέψεις με το mvc, γιατί το mvc πακέτο βασίζετε στο hero για τις μεθόδους του controller σου, οι ίδιοι κανόνες εφαρμόζονται και εκεί.

Παραδείγματα:

Αν χρησημοποιούσατε το MVC πριν, διαβάστε προσεχτικά: Το MVC ΠΕΡΙΕΧΕΙ ΟΡΙΣΜΕΝΕΣ ΑΛΛΑΓΕΣ, ΜΠΟΡΕΙΤΕ ΝΑ ΚΑΝΕΤΕ ΠΕΡΙΣΣΟΤΕΡΑ ΑΠΟ'ΤΙ ΠΡΙΝ

ΠΑΡΑΚΑΛΩ ΔΙΑΒΑΣΤΕ ΤΑ ΠΑΡΑΔΕΙΓΜΑΤΑ ΠΡΟΣΕΧΤΙΚΑ, ΓΙΑ ΕΣΑΣ ΦΤΙΑΧΤΗΚΑΝ

Τα παλιά παραδείγματα είναι επίσης εδώ ώστε να μπορείτε να τα συγκρίνετε με τα καινούρια.

ΤΩΡΑ ΠΡΙΝ
Hello world ΠΑΛΙΟ Hello world
Session Controller ΠΑΛΙΟ Session Controller
Overview - Plus Repository and Service layers ΠΑΛΙΟ Overview - Plus Repository and Service layers
Login showcase - Plus Repository and Service layers ΠΑΛΙΟ Login showcase - Plus Repository and Service layers
Singleton NEO
Websocket Controller NEO
Vue.js Todo MVC NEO

context#PostMaxMemory

Αφαίρεση της παλιάς στατικής μεταβλητής context.DefaultMaxMemory και αντικατάσταση με ρύθμιση στο configuration WithPostMaxMemory.

// WithPostMaxMemory sets the maximum post data size
// that a client can send to the server, this differs
// from the overral request body size which can be modified
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
//
// Defaults to 32MB or 32 << 20 if you prefer.
func WithPostMaxMemory(limit int64) Configurator

Αν χρησημοποιούσατε την παλιά στατική μεταβλητή θα χρειαστεί να κάνετε μια αλλαγή σε εκείνη τη γραμμή του κώδικα.

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    // [...]

    app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20))
}

context#UploadFormFiles

Νέα μέθοδος για ανέβασμα πολλαπλών αρχείων από τον client, πρέπει να χρησημοποιείται για απλές και συνηθισμένες καταστάσεις, ένα helper είναι μόνο.

// UploadFormFiles uploads any received file(s) from the client
// to the system physical location "destDirectory".
//
// The second optional argument "before" gives caller the chance to
// modify the *miltipart.FileHeader before saving to the disk,
// it can be used to change a file's name based on the current request,
// all FileHeader's options can be changed. You can ignore it if
// you don't need to use this capability before saving a file to the disk.
//
// Note that it doesn't check if request body streamed.
//
// Returns the copied length as int64 and
// a not nil error if at least one new file
// can't be created due to the operating system's permissions or
// http.ErrMissingFile if no file received.
//
// If you want to receive & accept files and manage them manually you can use the `context#FormFile`
// instead and create a copy function that suits your needs, the below is for generic usage.
//
// The default form's memory maximum size is 32MB, it can be changed by the
//  `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
//
// See `FormFile` to a more controlled to receive a file.
func (ctx *context) UploadFormFiles(
        destDirectory string,
        before ...func(string, string),
    ) (int64, error)

Το παράδειγμα μπορεί να βρεθεί εδώ.

context#View

Απλά μια μικρή προσθήκη μια δεύτερης προαιρετικής variadic παράμετρου στη context#View μέθοδο για να δέχεται μια μονή τιμή για template binding.
Όταν απλά θέλετε να εμφάνισετε ένα struct value και όχι ζεύγη από κλειδί-τιμή, παλιότερα για να το κάνετε αυτό έπρεπε να δηλώσετε κενό string στη 1η παράμετρο στη context#ViewData μέθοδο, το οποίο είναι μια χαρά ειδικά αν δηλώνατε αυτά τα δεδομένα σε προηγούμενο handler της αλυσίδας.

func(ctx iris.Context) {
    ctx.ViewData("", myItem{Name: "iris" })
    ctx.View("item.html")
}

Το ίδιο όπως:

func(ctx iris.Context) {
    ctx.View("item.html", myItem{Name: "iris" })
}
Item's name: {{.Name}}

context#YAML

Προσθήκη νέας μεθόδου, context#YAML, εμφανίζει δομημένο yaml κείμενο από struct value.

// YAML marshals the "v" using the yaml marshaler and renders its result to the client.
func YAML(v interface{}) (int, error)

Session#GetString

Η μέθοδος sessions/session#GetString μπορεί πλέον να επιστρέψει τιμή ακόμα και απο τιμή που αποθηκεύτηκαι σαν αριθμός (integer), όπως ακριβώς κάνουν ήδη τα: memstore, η προσωρινή μνήμη του context, οι δυναμικές μεταβλητές του path routing και οι παράμετροι του url query.

v10.0.0

@kataras kataras released this Jan 9, 2018 · 23 commits to master since this release

This is an on-going release

Promise of no breaking changes but new features and bug fixes(if any at this timeline we're now) may come. This tag release was created for people using glide and semantic version for their projects.

Mo, 01 Jenuary 2018 | v10.0.0

We must thanks Mrs. Diana for our awesome new logo!

You can contact her for any design-related enquiries or explore and send a direct message via instagram.

At this version we have many internal improvements but just two major changes and one big feature, called hero.

The new version adds 75 plus new commits, the PR is located here read the internal changes if you are developing a web framework based on Iris. Why 9 was skipped? Because.

Hero

The new package hero contains features for binding any object or function that handlers may use, these are called dependencies. Hero funcs can also return any type of values, these values will be dispatched to the client.

You may saw binding before but you didn't have code editor's support, with Iris you get truly safe binding thanks to the new hero package. It's also fast, near to raw handlers performance because Iris calculates everything before server ran!

Below you will see some screenshots we prepared for you in order to be easier to understand:

1. Path Parameters - Built'n Dependencies

2. Services - Static Dependencies

3. Per-Request - Dynamic Dependencies

hero funcs are very easy to understand and when you start using them you never go back.

Examples:

MVC

You have to understand the hero package in order to use the mvc, because mvc uses the hero internally for the controller's methods you use as routes, the same rules applied to those controller's methods of yours as well.

With this version you can register any controller's methods as routes manually, you can get a route based on a method name and change its Name (useful for reverse routing inside templates), you can use any dependencies registered from hero.Register or mvc.New(iris.Party).Register per mvc application or per-controller, you can still use BeginRequest and EndRequest, you can catch BeforeActivation(b mvc.BeforeActivation) to add dependencies per controller and AfterActivation(a mvc.AfterActivation) to make any post-validations, singleton controllers when no dynamic dependencies are used, Websocket controller, as simple as a websocket.Connection dependency and more...

Examples:

If you used MVC before then read very carefully: MVC CONTAINS SOME BREAKING CHANGES BUT YOU CAN DO A LOT MORE AND EVEN FASTER THAN BEFORE

PLEASE READ THE EXAMPLES CAREFULLY, WE'VE MADE THEM FOR YOU

Old examples are here as well. Compare the two different versions of each example to understand what you win if you upgrade now.

NEW OLD
Hello world OLD Hello world
Session Controller OLD Session Controller
Overview - Plus Repository and Service layers OLD Overview - Plus Repository and Service layers
Login showcase - Plus Repository and Service layers OLD Login showcase - Plus Repository and Service layers
Singleton NEW
Websocket Controller NEW
Vue.js Todo MVC NEW

context#PostMaxMemory

Remove the old static variable context.DefaultMaxMemory and replace it with the configuration WithPostMaxMemory.

// WithPostMaxMemory sets the maximum post data size
// that a client can send to the server, this differs
// from the overral request body size which can be modified
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
//
// Defaults to 32MB or 32 << 20 if you prefer.
func WithPostMaxMemory(limit int64) Configurator

If you used that old static field you will have to change that single line.

Usage:

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    // [...]

    app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20))
}

context#UploadFormFiles

New method to upload multiple files, should be used for common upload actions, it's just a helper function.

// UploadFormFiles uploads any received file(s) from the client
// to the system physical location "destDirectory".
//
// The second optional argument "before" gives caller the chance to
// modify the *miltipart.FileHeader before saving to the disk,
// it can be used to change a file's name based on the current request,
// all FileHeader's options can be changed. You can ignore it if
// you don't need to use this capability before saving a file to the disk.
//
// Note that it doesn't check if request body streamed.
//
// Returns the copied length as int64 and
// a not nil error if at least one new file
// can't be created due to the operating system's permissions or
// http.ErrMissingFile if no file received.
//
// If you want to receive & accept files and manage them manually you can use the `context#FormFile`
// instead and create a copy function that suits your needs, the below is for generic usage.
//
// The default form's memory maximum size is 32MB, it can be changed by the
//  `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument.
//
// See `FormFile` to a more controlled to receive a file.
func (ctx *context) UploadFormFiles(
        destDirectory string,
        before ...func(string, string),
    ) (int64, error)

Example can be found here.

context#View

Just a minor addition, add a second optional variadic argument to the context#View method to accept a single value for template binding.
When you just want one value and not key-value pairs, you used to use an empty string on the ViewData, which is fine, especially if you preload these from a previous handler/middleware in the request handlers chain.

func(ctx iris.Context) {
    ctx.ViewData("", myItem{Name: "iris" })
    ctx.View("item.html")
}

Same as:

func(ctx iris.Context) {
    ctx.View("item.html", myItem{Name: "iris" })
}
Item's name: {{.Name}}

context#YAML

Add a new context#YAML function, it renders a yaml from a structured value.

// YAML marshals the "v" using the yaml marshaler and renders its result to the client.
func YAML(v interface{}) (int, error)

Session#GetString

sessions/session#GetString can now return a filled value even if the stored value is a type of integer, just like the memstore, the context's temp store, the context's path parameters and the context's url parameters.

v8.5.9

@kataras kataras released this Dec 22, 2017 · 1 commit to v8 since this release

Merry Christmas - Final release of version 8 cycle

Relative links:

Fr, 22 Decemember 2017 | v8.5.9

This is the end of the version 8 cycle and a new beginning for the upcoming version release.

Read below the complete list of the latest changes of the v8 cycle.

Th, 09 November 2017 | v8.5.8

  • IMPROVE the Single Page Application builder* and fix #803 reported by @ionutvilie, a new example is located here.
    • app.SPA now returns the *SPABuilder and you can change some of its fields manually, i.e;
      • IndexNames defaulted to empty but can be seted to []{"index.html"} or call the new AddIndexName from the app.SPA manually if dynamic view on root has registered, see here how.
    • AssetValidator exists as it was and it's checked before the spa file server but it allows everything by-default because the real validation happens internally; if body was written or not, if not then reset the context's response writer and execute the router, as previously, otherwise release the context and send the response to the client.

Tu, 07 November 2017 | v8.5.7

Nothing crazy here, just one addition which may help some people;

Able to share configuration between multiple Iris instances based on the $home_path+iris.yml configuration file with the new iris.WithGlobalConfiguration configurator*.

Example:

package main
import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Get("/", func(ctx iris.Context) {
        ctx.HTML("<b>Hello!</b>")
    })
    // [...]

    // Good when you share configuration between multiple iris instances.
    // This configuration file lives in your $HOME/iris.yml for unix hosts
    // or %HOMEDRIVE%+%HOMEPATH%/iris.yml for windows hosts, and you can modify it.
    app.Run(iris.Addr(":8080"), iris.WithGlobalConfiguration)
    // or before run:
    // app.Configure(iris.WithGlobalConfiguration)
    // app.Run(iris.Addr(":8080"))
}

Su, 05 November 2017 | v8.5.6

TODO;

  • give the ability to customize the mvc path-method-and path parameters mapping,
  • make a github bot which will post the monthly usage and even earnings statistics in a public github markdown file, hope that users will love that type of transparency we will introduce here.

Th, 02 November 2017 | v8.5.5

  • fix audio/mpeg3 does not appear to be a valid registered mime type#798 reported by @kryptodev,
  • improve the updater's performance and moved that into the framework itself,
    • ask for authentication only when a new version is released.
  • sessiondb's .Async functions do nothing now, all session databases(back-end persistence storage) should run in-sync, @speedwheel helped to find a misbehavior because of that setting,
  • the configuration now has json fields tag like yaml and toml did in order to be able to be fetched from a json file directly using the encoding/json package,
  • fix the context#GetFloat64,
  • we are on opencollective and sponsored by codesponsor now.

TODO;

  • give the ability to customize the mvc path-method-and path parameters mapping,
  • make a github bot which will post the monthly usage and even earnings statistics in a public github markdown file, hope that users will love that type of transparency we will introduce here.

Th, 26 October 2017 | v8.5.4

This version is part of the releases.

Version Updater

Not any new features or fixes (all reported bugs are fixed) in this version, just a tiny improvement.

More friendly version checker!

Remember: If you don't want to keep the version checker and you're pretty sure that you will be able to keep your server up-to-date manually, then you can disable the auto updater via; app.Run(..., iris.WithoutVersionChecker).

We need your help with translations into your native language

Iris needs your help, please think about contributing to the translation of the README and https://iris-go.com, you will be rewarded.

Instructions can be found at: #796

Su, 22 October 2017 | v8.5.3

🎗️ People that you should follow

Help this project to continue deliver awesome and unique features with the higher code quality as possible by donating any amount via PayPal or BTC!

Name Amount Membership
Juan Sebastián Suárez Valencia 20 EUR Bronze
Bob Lee 20 EUR Bronze
Celso Luiz 50 EUR Silver
Ankur Srivastava 20 EUR Bronze
Damon Zhao 20 EUR Bronze
Exponity - Tech Company 30 EUR Bronze
Thomas Fritz 25 EUR Bronze
Thanos V. 20 EUR Bronze
George Opritescu 20 EUR Bronze
Lex Tang 20 EUR Bronze
Bill Q. 600 EUR Gold
Conrad Steenberg 25 EUR Bronze

Th, 12 October 2017 | v8.5.2

This version is part of the releases.

MVC

Add bool as a supported return value, if false then skips everything else and fires 404 not found.

New example which covers the Service and Repository layers side-by-side with the MVC Architectural pattern, clean and simple: _examples/mvc/overview.

Websocket

Fix(?) #782 by @jerson with PR: #783.

Minor

Add some minor comments for the view/django's origin type getters-- as pushed at PR: #765.

sessions/sessiondb/badger vendored with: e7517ec.

Tu, 10 October 2017 | v8.5.1

MVC

  • fix any manual or before middleware's ctx.ViewData(key, value) gets overridden by setting mvc.Controller.Data or return mvc.View {Data: ...}. See the test case.

Mo, 09 October 2017 | v8.5.0

MVC

Great news for our MVC Fans or if you're not you may want to use that powerful feature today, because of the smart coding and decisions the performance is quite the same to the pure handlers, see _benchmarks.

A Controller's field that is an interface can now be binded to any type that implements that interface.

Ability to send HTTP responses based on the Controller's method function's output values, see below;

Iris now gives you the ability to render a response based on the output values returned from the controller's method functions!

You can return any value of any type from a method function
and it will be sent to the client as expected.

  • if string then it's the body.
  • if string is the second output argument then it's the content type.
  • if int then it's the status code.
  • if error and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead.
  • if (int, error) and error is not nil then the response result will be the error's text with the status code as int.
  • if custom struct or interface{} or slice or map then it will be rendered as json, unless a string content type is following.
  • if mvc.Result then it executes its Dispatch function, so good design patters can be used to split the model's logic where needed.

The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before;

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/middleware/basicauth"
    "github.com/kataras/iris/mvc"
)

// Movie is our sample data structure.
type Movie struct {
    Name   string `json:"name"`
    Year   int    `json:"year"`
    Genre  string `json:"genre"`
    Poster string `json:"poster"`
}

// movies contains our imaginary data source.
var movies = []Movie{
    {
        Name:   "Casablanca",
        Year:   1942,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg",
    },
    {
        Name:   "Gone with the Wind",
        Year:   1939,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg",
    },
    {
        Name:   "Citizen Kane",
        Year:   1941,
        Genre:  "Mystery",
        Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg",
    },
    {
        Name:   "The Wizard of Oz",
        Year:   1939,
        Genre:  "Fantasy",
        Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg",
    },
}


var basicAuth = basicauth.New(basicauth.Config{
    Users: map[string]string{
        "admin": "password",
    },
})


func main() {
    app := iris.New()

    app.Use(basicAuth)

    app.Controller("/movies", new(MoviesController))

    app.Run(iris.Addr(":8080"))
}

// MoviesController is our /movies controller.
type MoviesController struct {
    // mvc.C is just a lightweight lightweight alternative
    // to the "mvc.Controller" controller type,
    // use it when you don't need mvc.Controller's fields
    // (you don't need those fields when you return values from the method functions).
    mvc.C
}

// Get returns list of the movies
// Demo:
// curl -i http://localhost:8080/movies
func (c *MoviesController) Get() []Movie {
    return movies
}

// GetBy returns a movie
// Demo:
// curl -i http://localhost:8080/movies/1
func (c *MoviesController) GetBy(id int) Movie {
    return movies[id]
}

// PutBy updates a movie
// Demo:
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
func (c *MoviesController) PutBy(id int) Movie {
    // get the movie
    m := movies[id]

    // get the request data for poster and genre
    file, info, err := c.Ctx.FormFile("poster")
    if err != nil {
        c.Ctx.StatusCode(iris.StatusInternalServerError)
        return Movie{}
    }
    file.Close()            // we don't need the file
    poster := info.Filename // imagine that as the url of the uploaded file...
    genre := c.Ctx.FormValue("genre")

    // update the poster
    m.Poster = poster
    m.Genre = genre
    movies[id] = m

    return m
}

// DeleteBy deletes a movie
// Demo:
// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1
func (c *MoviesController) DeleteBy(id int) iris.Map {
    // delete the entry from the movies slice
    deleted := movies[id].Name
    movies = append(movies[:id], movies[id+1:]...)
    // and return the deleted movie's name
    return iris.Map{"deleted": deleted}
}

Another good example with a typical folder structure, that many developers are used to work, is located at the new README.md under the Quick MVC Tutorial #3 section.

Fr, 06 October 2017 | v8.4.5

  • Badger team added support for transactions yesterday, therefore the badger session database is updated via 0b48927.
  • MVC: Support more than one path parameters with a single By, when the By keyword is the last word and the func's input arguments are more than one i.e GetBy(name string, age int), note that you can still use the older way of doing this; GetByBy(string, int). It's an enhancement of the #751 feature request.
  • MVC: Give controllers the ability to auto-initialize themselves by OnActivate func derives from the new ActivateListener interface, this can be used to perform any custom actions when the app registers the supported Controllers. See mvc/session_controller.go for a good use case.
  • errors.Reporter.AddErr returns true if the error is added to the stack, otherwise false.
  • @ZaniaDeveloper fixed #778 with PR: #779.
  • Add StatusSeeOther at mvc login example for Redirection, reported by @motecshine at #777.
  • Fix DisableVersionChecker configuration field is not being passed correctly when it was true via app.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...}) call.

Su, 01 October 2017 | v8.4.4

  • Fix #762 reported by @xkylsoft
  • Fix #771 reported by @cdren
  • Improvements to the memstore's GetInt, GetInt64, GetFloat64, GetBool and remove the golang/net/context's interface completion from Context, read the changes for more
  • Add two examples for folder structuring as requested at #748
  • Add node.js express benchmarks similar to iris and netcore

We, 27 September 2017 | v8.4.3

Fr, 15 September 2017 | v8.4.2

MVC

Support more than one dynamic method function receivers.

package main

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Controller("/user", new(UserController))
    app.Run(iris.Addr("localhost:8080"))
}

type UserController struct { iris.Controller }

// Maps to GET /user
// Request example: http://localhost:8080/user
// as usual.
func (c *UserController) Get() {
    c.Text = "hello from /user"
}

// Maps to GET /user/{paramfirst:long}
// Request example: http://localhost:8080/user/42
// as usual.
func (c *UserController) GetBy(userID int64) {
    c.Ctx.Writef("hello user with id: %d", userID)
}

// NEW:
// Maps to GET /user/{paramfirst:long}/business/{paramsecond:long}
// Request example: http://localhost:8080/user/42/business/93
func (c *UserController) GetByBusinessBy(userID int64, businessID int64) {
    c.Ctx.Writef("fetch a business id: %d that user with id: %d owns, may make your db query faster",
    businessID, userID)
}

Th, 07 September 2017 | v8.4.1

Routing

Add a macro type for booleans: app.Get("/mypath/{paramName:boolean}", myHandler).

+------------------------+
| {param:boolean}        |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"

Add context.Params().GetBool(paramName string) (bool, error) respectfully.

app := iris.New()
app.Get("/mypath/{has:boolean}", func(ctx iris.Context) { // <--
    // boolean first return value
    // error as second return value
    //
    // error will be always nil here because
    // we use the {has:boolean} so router
    // makes sure that the parameter is a boolean
    // otherwise it will return a 404 not found http error code
    // skipping the call of this handler.
    has, _ := ctx.Params().GetBool("has") // <--
    if has {
        ctx.HTML("<strong>it's true</strong>")
    }else {
        ctx.HTML("<strong>it's false</string>")
    }
})
// [...]

MVC

Support for boolean method receivers, i.e GetBy(bool), PostBy(bool)....

app := iris.New()

app.Controller("/equality", new(Controller))
type Controller struct {
    iris.Controller
}

// handles the "/equality" path.
func (c *Controller) Get() {

}

// registers and handles the path: "/equality/{param:boolean}".
func (c *Controller) GetBy(is bool) { // <--
    // [...]
}

Supported types for method functions receivers are: int, int64, bool and string.

Su, 27 August 2017 | v8.4.0

Miscellaneous

Router

Add a new macro type for path parameters, long, it's the go type int64.

app.Get("/user/{id:long}", func(ctx context.Context) {
	userID, _ := ctx.Params().GetInt64("id")
})

MVC

The ability to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that after a go get -u github.com/kataras/iris you will be able to use things like these:

If app.Controller("/user", new(user.Controller))

  • func(*Controller) Get() - GET:/user , as usual.
  • func(*Controller) Post() - POST:/user, as usual.
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

If app.Controller("/profile", new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

If app.Controller("/assets", new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

Example can be found at: _examples/mvc/login/user/controller.go.

Pretty awesome, right?

We, 23 August 2017 | v8.3.4

Give read access to the current request context's route, a feature that many of you asked a lot.

func(ctx context.Context) {
	_ = ctx.GetCurrentRoute().Name()
	//					.Method() returns string, same as ctx.Method().
	//					.Subdomain() returns string, the registered subdomain.
	//					.Path() returns string, the registered path.
	//					.IsOnline() returns boolean.
}
type MyController struct {
	mvc.Controller
}

func (c *MyController) Get(){
	_ = c.Route().Name() // same as `c.Ctx.GetCurrentRoute().Name()`.
	// [...]
}

Updated: 24 August 2017

This evening, on the next version 8.3.5:

Able to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that in the future you will be able to use something like these:

If app.Controller("/user", new(user.Controller))

  • func(c *Controller) Get() - GET:/user , as usual.
  • func(c *Controller) Post() - POST:/user, as usual.
  • func(c *Controller) GetLogin() - GET:/user/login
  • func(c *Controller) PostLogin() - POST:/user/login
  • func(c *Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(c *Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(c *Controller) GetBy() - GET:/user/{param}
  • func(c *Controller) GetByName(name string) - GET:/user/{name}
  • func(c *Controller) PostByName(name string) - POST:/user/{name}
  • func(c *Controller) GetByID(id int64 || int) - GET:/user/{id:int}
  • func(c *Controller) PostByID(id int64 || int) - POST:/user/{id:int}

Watch and stay tuned my friends.

We, 23 August 2017 | v8.3.3

Better debug messages when using MVC.

Add support for recursively binding and custom controllers embedded to other custom controller, that's the new feature. That simply means that Iris users are able to use "shared" controllers everywhere; when binding, using models, get/set persistence data, adding middleware, intercept request flow.

This will help web authors to split the logic at different controllers. Those controllers can be also used as "standalone" to serve a page somewhere else in the application as well.

My personal advice to you is to always organize and split your code nicely and wisely in order to avoid using such as an advanced MVC feature, at least any time soon.

I'm aware that this is not always an easy task to do, therefore is here if you ever need it :)

A ridiculous simple example of this feature can be found at the mvc/controller_test.go file.

Tu, 22 August 2017 | v8.3.2

MVC

When one or more values of handler type (func(ctx context.Context)) are passed
right to the controller initialization then they will be recognised and act as middleware(s)
that ran even before the controller activation, there is no reason to load
the whole controller if the main handler or its BeginRequest are not "allowed" to be executed.

Example Code

func checkLogin(ctx context.Context) {
	if !myCustomAuthMethodPassed {
		// [set a status or redirect, you know what to do]
		ctx.StatusCode(iris.StatusForbidden)
		return
	}

	// [continue to the next handler, at this example is our controller itself]
	ctx.Next()
}

// [...]
app.Controller(new(ProfileController), checkLogin)
// [...]

Usage of these kind of MVC features could be found at the mvc/controller_test.go file.

Other minor enhancements

  • fix issue #726*
  • fix redis sessiondb expiration*
  • update recursively when new version is available*
  • some minor session enhancements*

Sa, 19 August 2017 | v8.3.1

First of all I want to thank you for the 100% green feedback you gratefully sent me you about
my latest article Go vs .NET Core in terms of HTTP performance, published at medium's hackernoon.com and dev.to. I really appreciate it💓

No API Changes.

However two more methods added to the Controller.

  • RelPath() string, returns the relative path based on the controller's name and the request path.
  • RelTmpl() string, returns the relative template directory based on the controller's name.

These are useful when dealing with big controllers, they help you to keep align with any
future changes inside your application.

Want to learn more about these functions? Go to the mvc/controller_test.go file and scroll to the bottom!

Fr, 18 August 2017 | v8.3.0

Good news for devs that are used to write their web apps using the MVC architecture pattern.

Implement a whole new mvc package with additional support for models and easy binding.

@kataras started to develop that feature by version 8.2.5, back then it didn't seem
to be a large feature and maybe a game-changer, so it lived inside the kataras/iris/core/router/controller.go file.
However with this version, so many things are implemented for the MVC and we needed a new whole package,
this new package is the kataras/iris/mvc, but if you used go 1.9 to build then you don't have to do any refactor, you could use the iris.Controller type alias.

People who used the mvc from its baby steps(v8.2.5) the only syntactic change you'll have to do is to rename the router.Controller to mvc.Controller:

Before:

import "github.com/kataras/iris/core/router"
type MyController struct {
    router.Controller
}

Now:

import "github.com/kataras/iris/mvc"
type MyController struct {
    mvc.Controller
    // if you build with go1.9 you can omit the import of mvc package
    // and just use `iris.Controller` instead.
}

MVC (Model View Controller)

From version 8.3 and after Iris has first-class support for the MVC pattern, you'll not find
these stuff anywhere else in the Go world.

Example Code

package main

import (
	"sync"

	"github.com/kataras/iris"
	"github.com/kataras/iris/mvc"
)

func main() {
	app := iris.New()
	app.RegisterView(iris.HTML("./views", ".html"))

	// when we have a path separated by spaces
	// then the Controller is registered to all of them one by one.
	//
	// myDB is binded to the controller's `*DB` field: use only structs and pointers.
	app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
		new(ProfileController), myDB) // IMPORTANT

	app.Run(iris.Addr(":8080"))
}

// UserModel our example model which will render on the template.
type UserModel struct {
	ID       int64
	Username string
}

// DB is our example database.
type DB struct {
	usersTable map[int64]UserModel
	mu         sync.RWMutex
}

// GetUserByID imaginary database lookup based on user id.
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
	db.mu.RLock()
	u, found = db.usersTable[id]
	db.mu.RUnlock()
	return
}

var myDB = &DB{
	usersTable: map[int64]UserModel{
		1:  {1, "kataras"},
		2:  {2, "makis"},
		42: {42, "jdoe"},
	},
}

// ProfileController our example user controller which controls
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
type ProfileController struct {
	mvc.Controller // IMPORTANT

	User UserModel `iris:"model"`
	// we will bind it but you can also tag it with`iris:"persistence"`
	// and init the controller with manual &PorifleController{DB: myDB}.
	DB *DB
}

// Get method handles all "GET" HTTP Method requests of the controller's paths.
func (pc *ProfileController) Get() { // IMPORTANT
	path := pc.Path

	// requested: /profile path
	if path == "/profile" {
		pc.Tmpl = "profile/index.html"
		return
	}
	// requested: /profile/browse
	// this exists only to proof the concept of changing the path:
	// it will result to a redirection.
	if path == "/profile/browse" {
		pc.Path = "/profile"
		return
	}

	// requested: /profile/me path
	if path == "/profile/me" {
		pc.Tmpl = "profile/me.html"
		return
	}

	// requested: /profile/$ID
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound
		pc.Tmpl = "profile/notfound.html"
		pc.Data["ID"] = id
		return
	}

	pc.Tmpl = "profile/profile.html"
	pc.User = user
}


/*
func (pc *ProfileController) Post() {}
func (pc *ProfileController) Put() {}
func (pc *ProfileController) Delete() {}
func (pc *ProfileController) Connect() {}
func (pc *ProfileController) Head() {}
func (pc *ProfileController) Patch() {}
func (pc *ProfileController) Options() {}
func (pc *ProfileController) Trace() {}
*/

/*
func (pc *ProfileController) All() {}
//        OR
func (pc *ProfileController) Any() {}
*/

Iris web framework supports Request data, Models, Persistence Data and Binding
with the fastest possible execution.

Characteristics

All HTTP Methods are supported, for example if want to serve GET
then the controller should have a function named Get(),
you can define more than one method function to serve in the same Controller struct.

Persistence data inside your Controller struct (share data between requests)
via iris:"persistence" tag right to the field or Bind using app.Controller("/" , new(myController), theBindValue).

Models inside your Controller struct (set-ed at the Method function and rendered by the View)
via iris:"model" tag right to the field, i.e User UserModel `iris:"model" name:"user"` view will recognise it as {{.user}}.
If name tag is missing then it takes the field's name, in this case the "User".

Access to the request path and its parameters via the Path and Params fields.

Access to the template file that should be rendered via the Tmpl field.

Access to the template data that should be rendered inside
the template file via Data field.

Access to the template layout via the Layout field.

Access to the low-level context.Context via the Ctx field.

Get the relative request path by using the controller's name via RelPath().

Get the relative template path directory by using the controller's name via RelTmpl().

Flow as you used to, Controllers can be registered to any Party,
including Subdomains, the Party's begin and done handlers work as expected.

Optional BeginRequest(ctx) function to perform any initialization before the method execution,
useful to call middlewares or when many methods use the same collection of data.

Optional EndRequest(ctx) function to perform any finalization after any method executed.

Inheritance, recursively, see for example our mvc.SessionController, it has the mvc.Controller as an embedded field
and it adds its logic to its BeginRequest, here.

Read access to the current route via the Route field.

Using Iris MVC for code reuse

By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.

If you're new to back-end web development read about the MVC architectural pattern first, a good start is that wikipedia article.

Follow the examples below,

https://github.com/kataras/iris/tree/v8/_examples/#mvc

Bugs

Fix #723 reported by @speedwheel.

Mo, 14 August 2017 | v8.2.6

Able to call done/end handlers inside a Controller, via optional EndRequest(ctx context.Context) function inside the controller struct.

// it's called after t.Get()/Post()/Put()/Delete()/Connect()/Head()/Patch()/Options()/Trace().
func (t *testControllerEndRequestFunc) EndRequest(ctx context.Context) {
    // 2.
    // [your code goes here...]
}

// will handle "GET" request HTTP method only.
func (t *testControllerEndRequestFunc) Get() {
    // 1.
    // [your code goes here...]
}

Look at the v8.2.5 changelog to learn more about the new Iris Controllers feature.

Su, 13 August 2017 | v8.2.5

Good news for devs that are used to write their web apps using the MVC-style app architecture.

Yesterday I wrote a tutorial on how you can transform your raw Handlers to Controllers using the existing tools only (Iris is the most modular web framework out there, we all have no doubt about this).

Today, I did implement the Controller idea as built'n feature inside Iris.
Our Controller supports many things among them are:

  • all HTTP Methods are supported, for example if want to serve GET then the controller should have a function named Get(), you can define more than one method function to serve in the same Controller struct
  • persistence data inside your Controller struct (share data between requests) via iris:"persistence" tag right to the field
  • optional BeginRequest(ctx) function to perform any initialization before the methods, useful to call middlewares or when many methods use the same collection of data
  • optional EndRequest(ctx) function to perform any finalization after the methods executed
  • access to the request path parameters via the Params field
  • access to the template file that should be rendered via the Tmpl field
  • access to the template data that should be rendered inside the template file via Data field
  • access to the template layout via the Layout field
  • access to the low-level context.Context via the Ctx field
  • flow as you used to, Controllers can be registered to any Party, including Subdomains, the Party's begin and done handlers work as expected.

It's very easy to get started, the only function you need to call instead of app.Get/Post/Put/Delete/Connect/Head/Patch/Options/Trace is the app.Controller.

Example Code:

// file: main.go

package main

import (
    "github.com/kataras/iris"

    "controllers"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    app.Controller("/", new(controllers.Index))

    // http://localhost:8080/
    app.Run(iris.Addr(":8080"))
}
// file: controllers/index.go

package controllers

import (
    "github.com/kataras/iris/core/router"
)

// Index is our index example controller.
type Index struct {
    mvc.Controller
    // if you're using go1.9: 
    // you can omit the /core/router import statement
    // and just use the `iris.Controller` instead.
}

// will handle GET method on http://localhost:8080/
func (c *Index) Get() {
    c.Tmpl = "index.html"
    c.Data["title"] = "Index page"
    c.Data["message"] = "Hello world!"
}

// will handle POST method on http://localhost:8080/
func (c *Index) Post() {}

Tip: declare a func(c *Index) All() {} or Any() to register all HTTP Methods.

A full example can be found at the _examples/mvc folder.

Sa, 12 August 2017 | v8.2.4

No API Changes.

Fix #717, users are welcomed to follow the thread for any questions or reports about Gzip and Static Files Handlers only.

Th, 10 August 2017 | v8.2.3

No API Changes.

Fix #714

Continue to v8.2.2 for more...

Th, 10 August 2017 | v8.2.2

No API Changes.

  • Implement Google reCAPTCHA middleware, example here
  • Fix kataras/golog prints with colors on windows server 2012 while it shouldn't because its command line tool does not support 256bit colors
  • Improve the updater by a custom self-updated back-end version checker, can be disabled by:
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)

Or

app.Configure(iris.WithoutVersionChecker)

Or

app.Configure(iris.WithConfiguration(iris.Configuration{DisableVersionChecker:true}))

Tu, 08 August 2017 | v8.2.1

No API Changes. Great news for the unique iris sessions library, once again.

NEW: LevelDB-based session database implemented, example here.

Redis-based sessiondb has no longer the MaxAgeSeconds config field,
this is passed automatically by the session manager, now.

All sessions databases have an Async(bool) function, if turned on
then all synchronization between the memory store and the back-end database will happen
inside different go routines. By-default async is false but it's recommended to turn it on, it will make sessions to be stored faster, at most.

All reported issues have been fixed, the API is simplified by v8.2.0 so everyone can
create and use any back-end storage for application's sessions persistence.

Mo, 07 August 2017 | v8.2.0

No Common-API Changes.

Good news for iris sessions back-end databases users.

Info for session database authors Session Database API Changed to:
type Database interface {
	Load(sid string) RemoteStore
	Sync(p SyncPayload)
}

// SyncPayload reports the state of the session inside a database sync action.
type SyncPayload struct {
	SessionID string

	Action Action
	// on insert it contains the new key and the value
	// on update it contains the existing key and the new value
	// on delete it contains the key (the value is nil)
	// on clear it contains nothing (empty key, value is nil)
	// on destroy it contains nothing (empty key, value is nil)
	Value memstore.Entry
	// Store contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Store RemoteStore
}


// RemoteStore is a helper which is a wrapper
// for the store, it can be used as the session "table" which will be
// saved to the session database.
type RemoteStore struct {
	// Values contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Values memstore.Store
	// on insert it contains the expiration datetime
	// on update it contains the new expiration datetime(if updated or the old one)
	// on delete it will be zero
	// on clear it will be zero
	// on destroy it will be zero
	Lifetime LifeTime
}

Read more at sessions/database.go, view how three built'n session databases are being implemented here.

All sessions databases are updated and they performant even faster than before.

  • NEW raw file-based session database implemented, example here
  • NEW boltdb-based session database implemented, example here (recommended as it's safer and faster)
  • redis sessiondb updated to the latest api

Under the cover, session database works entirely differently than before but nothing changed from the user's perspective, so upgrade with go get -u github.com/kataras/iris and sleep well.

Tu, 01 August 2017 | v8.1.3

  • Add Option function to the html view engine: #694
  • Fix sessions backend databases restore expiration: #692 by @corebreaker
  • Add PartyFunc, same as Party but receives a function with the sub router as its argument instead [GO1.9 Users-ONLY]

Mo, 31 July 2017 | v8.1.2

Add a ConfigureHost function as an alternative way to customize the hosts via host.Configurator.
The first way was to pass host.Configurator as optional arguments on iris.Runners built'n functions (iris#Server, iris#Listener, iris#Addr, iris#TLS, iris#AutoTLS), example of this can be found there.

Example Code:

package main

import (
	stdContext "context"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/host"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx context.Context) {
		ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
	})

    app.ConfigureHost(configureHost) // or pass "configureHost" as `app.Addr` argument, same result.

	app.Logger().Info("Wait 10 seconds and check your terminal again")
	// simulate a shutdown action here...
	go func() {
		<-time.After(10 * time.Second)
		timeout := 5 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		// close all hosts, this will notify the callback we had register
		// inside the `configureHost` func.
		app.Shutdown(ctx)
	}()

	// http://localhost:8080
	// wait 10 seconds and check your terminal.
	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func configureHost(su *host.Supervisor) {
	// here we have full access to the host that will be created
	// inside the `app.Run` or `app.NewHost` function .
	//
	// we're registering a shutdown "event" callback here:
	su.RegisterOnShutdown(func() {
		println("server is closed")
	})
	// su.RegisterOnError
	// su.RegisterOnServe
}

Su, 30 July 2017

Greetings my friends, nothing special today, no version number yet.

We just improve the, external, Iris Logging library and the Columns config field from middleware/logger defaults to false now. Upgrade with go get -u github.com/kataras/iris and have fun!

Sa, 29 July 2017 | v8.1.1

No breaking changes, just an addition to make your life easier.

This feature has been implemented after @corebreaker 's request, posted at: #688. He was also tried to fix that by a PR, we thanks him but the problem with that PR was the duplication and the separation of concepts, however we thanks him for pushing for a solution. The current feature's implementation gives a permant solution to host supervisor access issues.

Optional host configurators added to all common serve and listen functions.

Below you'll find how to gain access to the host, the second way is the new feature.

Hosts

Access to all hosts that serve your application can be provided by
the Application#Hosts field, after the Run method.

But the most common scenario is that you may need access to the host before the Run method,
there are two ways of gain access to the host supervisor, read below.

First way is to use the app.NewHost to create a new host
and use one of its Serve or Listen functions
to start the application via the iris#Raw Runner.
Note that this way needs an extra import of the net/http package.

Example Code:

h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){
    println("server was closed!")
})

app.Run(iris.Raw(h.ListenAndServe))

Second, and probably easier way is to use the host.Configurator.

Note that this method requires an extra import statement of
"github.com/kataras/iris/core/host" when using go < 1.9,
if you're targeting on go1.9 then you can use the iris#Supervisor
and omit the extra host import.

All common Runners we saw earlier (iris#Addr, iris#Listener, iris#Server, iris#TLS, iris#AutoTLS)
accept a variadic argument of host.Configurator, there are just func(*host.Supervisor).
Therefore the Application gives you the rights to modify the auto-created host supervisor through these.

Example Code:

package main

import (
    stdContext "context"
    "time"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
    "github.com/kataras/iris/core/host"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
        ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
    })

    app.Logger().Info("Wait 10 seconds and check your terminal again")
    // simulate a shutdown action here...
    go func() {
        <-time.After(10 * time.Second)
        timeout := 5 * time.Second
        ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
        defer cancel()
        // close all hosts, this will notify the callback we had register
        // inside the `configureHost` func.
        app.Shutdown(ctx)
    }()

    // start the server as usual, the only difference is that
    // we're adding a second (optional) function
    // to configure the just-created host supervisor.
    //
    // http://localhost:8080
    // wait 10 seconds and check your terminal.
    app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed))

}

func configureHost(su *host.Supervisor) {
    // here we have full access to the host that will be created
    // inside the `Run` function.
    //
    // we register a shutdown "event" callback
    su.RegisterOnShutdown(func() {
        println("server is closed")
    })
    // su.RegisterOnError
    // su.RegisterOnServe
}

Read more about listening and gracefully shutdown by navigating to: https://github.com/kataras/iris/tree/v8/_examples/#http-listening

We, 26 July 2017 | v8.1.0

The app.Logger() *logrus.Logger was replaced with a custom implementation [golog], it's compatible with the logrus package and other open-source golang loggers as well, because of that: #680 (comment).

The API didn't change much except these:

  • the new implementation does not recognise Fatal and Panic because, actually, iris never panics
  • the old app.Logger().Out = io.Writer should be written as app.Logger().SetOutput(io.Writer)

The new implementation, golog is featured, three times faster than logrus
and it completes every common usage.

Integration

I understand that many of you may use logrus outside of Iris too. To integrate an external logrus logger just
Install it-- all print operations will be handled by the provided logrus instance.

import (
    "github.com/kataras/iris"
    "github.com/sirupsen/logrus"
)

package main(){
    app := iris.New()
    app.Logger().Install(logrus.StandardLogger()) // the package-level logrus instance
    // [...]
}

For more information about our new logger please navigate to: https://github.com/kataras/golog - contributions are welcomed as well!

Sa, 23 July 2017 | v8.0.7

Fix It's true that with UseGlobal the "/path1.txt" route call the middleware but cause the prepend, the order is inversed

Sa, 22 July 2017 | v8.0.5 & v8.0.6

No API Changes.

Performance

Add an experimental Configuration#EnableOptimizations option.

type Configuration {
    // [...]

    // EnableOptimization when this field is true
    // then the application tries to optimize for the best performance where is possible.
    //
    // Defaults to false.
    EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"`

    // [...]
}

Usage:

app.Run(iris.Addr(":8080"), iris.WithOptimizations)

Django view engine

@corebreaker pushed a PR to solve the Problem for {%extends%} in Django Engine with embedded files.

Logger

Remove the vendor/github.com/sirupsen/logrus folder, as a temporary solution for the #680 (comment).

Future versions

The logrus will be replaced with a custom implementation, because of that: #680 (comment).

As far as we know, @kataras is working on this new implementation, see here,
which will be compatible with the logrus package and other open-source golang loggers as well.

Mo, 17 July 2017 | v8.0.4

No API changes.

HTTP Errors

Fix a rare behavior: error handlers are not executed correctly
when a before-handler by-passes the order of execution, relative to the previous feature.

Request Logger

Add Configuration#MessageContextKey. Example can be found at _examples/http_request/request-logger/main.go.

Su, 16 July 2017 | v8.0.3

No API changes.

Relative issues:

HTTP Errors

Able to register a chain of Handlers (and middleware with ctx.Next() support like routes) for a specific error code, read more at issues/674. Usage example can be found at _examples/http_request/request-logger/main.go.

New function to register a Handler or a chain of Handlers for all official http error codes, by calling the new app.OnAnyErrorCode(func(ctx context.Context){}), read more at issues/675. Usage example can be found at _examples/http_request/request-logger/main.go.

Request Logger

Add Configuration#LogFunc and Configuration#Columns fields, read more at issues/676. Example can be found at _examples/http_request/request-logger/request-logger-file/main.go.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Sa, 15 July 2017 | v8.0.2

Okay my friends, this is a good time to upgrade, I did implement a feature that you were asking many times at the past.

Iris' router can now handle root-level wildcard paths app.Get("/{paramName:path}).

In case you're wondering: no it does not conflict with other static or dynamic routes, meaning that you can code something like this:

// it isn't conflicts with the rest of the static routes or dynamic routes with a path prefix.
app.Get("/{pathParamName:path}", myHandler) 

Or even like this:

package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
)

func main() {
	app := iris.New()

	// this works as expected now,
	// will handle all GET requests
	// except:
	// /                     -> because of app.Get("/", ...)
	// /other/anything/here  -> because of app.Get("/other/{paramother:path}", ...)
	// /other2/anything/here -> because of app.Get("/other2/{paramothersecond:path}", ...)
	// /other2/static        -> because of app.Get("/other2/static", ...)
	//
	// It isn't conflicts with the rest of the routes, without routing performance cost!
	//
	// i.e /something/here/that/cannot/be/found/by/other/registered/routes/order/not/matters
	app.Get("/{p:path}", h)

	// this will handle only GET /
	app.Get("/", staticPath)

	// this will handle all GET requests starting with "/other/"
	//
	// i.e /other/more/than/one/path/parts
	app.Get("/other/{paramother:path}", other)

	// this will handle all GET requests starting with "/other2/"
	// except /other2/static (because of the next static route)
	//
	// i.e /other2/more/than/one/path/parts
	app.Get("/other2/{paramothersecond:path}", other2)

	// this will handle only GET /other2/static
	app.Get("/other2/static", staticPath)

	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func h(ctx context.Context) {
	param := ctx.Params().Get("p")
	ctx.WriteString(param)
}

func other(ctx context.Context) {
	param := ctx.Params().Get("paramother")
	ctx.Writef("from other: %s", param)
}

func other2(ctx context.Context) {
	param := ctx.Params().Get("paramothersecond")
	ctx.Writef("from other2: %s", param)
}

func staticPath(ctx context.Context) {
	ctx.Writef("from the static path: %s", ctx.Path())
}

If you find any bugs with this change please send me a chat message in order to investigate it, I'm totally free at weekends.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Th, 13 July 2017 | v8.0.1

Nothing tremendous at this minor version.

We've just added a configuration field in order to ignore errors received by the Run function, see below.

Configuration#IgnoreServerErrors

type Configuration struct {
    // [...]

    // IgnoreServerErrors will cause to ignore the matched "errors"
    // from the main application's `Run` function.
    // This is a slice of string, not a slice of error
    // users can register these errors using yaml or toml configuration file
    // like the rest of the configuration fields.
    //
    // See `WithoutServerError(...)` function too.
    //
    // Defaults to an empty slice.
    IgnoreServerErrors []string `yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`

    // [...]
}

Configuration#WithoutServerError

// WithoutServerError will cause to ignore the matched "errors"
// from the main application's `Run` function.
//
// Usage:
// err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
//
// See `Configuration#IgnoreServerErrors []string` too.
WithoutServerError(errors ...error) Configurator

By default no error is being ignored, of course.

Example code:
_examples/http-listening/listen-addr/omit-server-errors

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
    	ctx.HTML("<h1>Hello World!/</h1>")
    })

    err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    if err != nil {
        // do something
    }
    // same as:
    // err := app.Run(iris.Addr(":8080"))
    // if err != nil && (err != iris.ErrServerClosed || err.Error() != iris.ErrServerClosed.Error()) {
    //     [...]
    // }
}

At first we didn't want to implement something like that because it's ridiculous easy to do it manually but a second thought came to us,
that many applications are based on configuration, therefore it would be nice to have something to ignore errors
by simply string values that can be passed to the application's configuration via toml or yaml files too.

This feature has been implemented after a request of ignoring the iris/http#ErrServerClosed from the Run function:
#668

Mo, 10 July 2017 | v8.0.0

📈 One and a half years with Iris and You...

Despite the deflamations, the clickbait articles, the removed posts of mine at reddit/r/golang, the unexpected and inadequate ban from the gophers slack room by @dlsniper alone the previous week without any reason or inform, Iris is still here and will be.

  • 7070 github stars
  • 749 github forks
  • 1m total views at its documentation
  • ~800$ at donations (there're a lot for a golang open-source project, thanks to you)
  • ~550 reported bugs fixed
  • ~30 community feature requests have been implemented

🔥 Reborn

As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore.

After a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community.

The leadership of this, open-source, repository was transferred to hiveminded, the author of iris-based get-ion/ion, he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s).

UPDATE:

I am voluntarily quiting this responsibility because I've been re-positioned as the new Lead Product Manager of the company I'm working for many years, which I accepted with honor. That's a very time consuming position I'm responsible to accomplish and deliver, therefore, I transfer all my rights back to @kataras and I resign from any copyrights over this project. My contribution clearly didn't make the difference but I owe a big "thank you" to Gerasimos for the chance he gave me and I hope the bests for him and iris. Thank you all.

These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me!

📰 Changelog

app. = app := iris.New(); app.

ctx. = func(ctx context.Context) { ctx. }

Docker

Docker and kubernetes integration showcase, see the iris-contrib/cloud-native-go repository as an example.

Logger

  • Logger which was an io.Writer was replaced with the pluggable logrus.
    • which you still attach an io.Writer with app.Logger().Out = an io.Writer.
    • iris as always logs only critical errors, you can disable them with app.Logger().Level = iris.NoLog
    • the request logger outputs the incoming requests as INFO level.

Sessions

Remove ctx.Session() and app.AttachSessionManager, devs should import and use the sessions package as standalone, it's totally optional, devs can use any other session manager too. Examples here.

Websockets

The github.com/kataras/iris/websocket package does not handle the endpoint and client side automatically anymore. Example code:

func setupWebsocket(app *iris.Application) {
    // create our echo websocket server
    ws := websocket.New(websocket.Config{
    	ReadBufferSize:  1024,
    	WriteBufferSize: 1024,
    })
    ws.OnConnection(handleConnection)
    // serve the javascript built'n client-side library,
    // see weboskcets.html script tags, this path is used.
    app.Any("/iris-ws.js", func(ctx context.Context) {
    	ctx.Write(websocket.ClientSource)
    })

    // register the server on an endpoint.
    // see the inline javascript code in the websockets.html, this endpoint is used to connect to the server.
    app.Get("/echo", ws.Handler())
}

More examples here

View

Rename app.AttachView(...) to app.RegisterView(...).

Users can omit the import of github.com/kataras/iris/view and use the github.com/kataras/iris package to
refer to the view engines, i.e: app.RegisterView(iris.HTML("./templates", ".html")) is the same as import "github.com/kataras/iris/view" [...] app.RegisterView(view.HTML("./templates" ,".html")).

Examples here

Security

At previous versions, when you called ctx.Remoteaddr() Iris could parse and return the client's IP from the "X-Real-IP", "X-Forwarded-For" headers. This was a security leak as you can imagine, because the user can modify them. So we've disabled these headers by-default and add an option to add/remove request headers that are responsible to parse and return the client's real IP.

// WithRemoteAddrHeader enables or adds a new or existing request header name
// that can be used to validate the client's real IP.
//
// Existing values are:
// "X-Real-Ip":             false,
// "X-Forwarded-For":       false,
// "CF-Connecting-IP": false
//
// Look `context.RemoteAddr()` for more.
WithRemoteAddrHeader(headerName string) Configurator // enables a header.
WithoutRemoteAddrHeader(headerName string) Configurator // disables a header.

For example, if you want to enable the "CF-Connecting-IP" header (cloudflare)
you have to add the WithRemoteAddrHeader option to the app.Run function, at the end of your program.

app.Run(iris.Addr(":8080"), iris.WithRemoteAddrHeader("CF-Connecting-IP"))
// This header name will be checked when ctx.RemoteAddr() called and if exists
// it will return the client's IP, otherwise it will return the default *http.Request's `RemoteAddr` field.

Miscellaneous

Fix typescript tools.

_examples folder has been ordered by feature and usage:
- contains tests on some examples
- new examples added, one of them shows how the reuseport feature on UNIX and BSD systems can be used to listen for incoming connections, see here

Replace supervisor's tasks with events, like RegisterOnShutdown, RegisterOnError, RegisterOnServe and fix the (unharmful) race condition when output the banner to the console. Global notifier for interrupt signals which can be disabled via app.Run([...], iris.WithoutInterruptHandler), look graceful-shutdown example for more.

More handlers are ported to Iris (they can be used as they are without iris.FromStd), these handlers can be found at iris-contrib/middleware. Feel free to put your own there.

Middleware Description Example
jwt Middleware checks for a JWT on the Authorization header on incoming requests and decodes it. iris-contrib/middleware/jwt/_example
cors HTTP Access Control. iris-contrib/middleware/cors/_example
secure Middleware that implements a few quick security wins. iris-contrib/middleware/secure/_example
tollbooth Generic middleware to rate-limit HTTP requests. iris-contrib/middleware/tollbooth/_examples/limit-handler
cloudwatch AWS cloudwatch metrics middleware. iris-contrib/middleware/cloudwatch/_example
new relic Official New Relic Go Agent. iris-contrib/middleware/newrelic/_example
prometheus Easily create metrics endpoint for the prometheus instrumentation tool iris-contrib/middleware/prometheus/_example

v7.x is deprecated because it sold as it is and it is not part of the public, stable gopkg.in iris versions. Developers/users of this library should upgrade their apps to v8.x, the refactor process will cost nothing for most of you, as the most common API remains as it was. The changelog history from that are being presented below.

Th, 15 June 2017 | v7.2.0

About our new home page

https://iris-go.com

Thanks to Santosh Anand the https://iris-go.com has been upgraded and it's really awesome!

Santosh is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.

The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!

Cache

Declare the iris.Cache alias to the new, improved and most-suited for common usage, cache.Handler function.

iris.Cache be used as middleware in the chain now, example here. However you can still use the cache as a wrapper by importing the github.com/kataras/iris/cache package.

File server

  • Fix that.

  • app.StaticHandler(requestPath string, systemPath string, showList bool, gzip bool) -> app.StaticHandler(systemPath,showList bool, gzip bool)

  • New feature for Single Page Applications, app.SPA(assetHandler context.Handler) implemented.

  • New app.StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) added in order to be able to pass that on app.SPA(app.StaticEmbeddedHandler("./public", Asset, AssetNames)).

  • Fix app.StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string).

Examples:

app.StaticWeb doesn't works for root request path "/" anymore, use the new app.SPA instead.

WWW subdomain entry

  • Example added to copy all application's routes, including parties, to the www.mydomain.com

Wrapping the Router

  • Example added to show you how you can use the app.WrapRouter
    to implement a similar to app.SPA functionality, don't panic, it's easier than it sounds.

Testing

  • httptest.New(app *iris.Application, t *testing.T) -> httptest.New(t *testing.T, app *iris.Application).

  • New httptest.NewLocalListener() net.Listener added.

  • New httptest.NewLocalTLSListener(tcpListener net.Listener) net.Listener added.

Useful for testing tls-enabled servers:

Proxies are trying to understand local addresses in order to allow InsecureSkipVerify.

  • host.ProxyHandler(target *url.URL) *httputil.ReverseProxy.

  • host.NewProxy(hostAddr string, target *url.URL) *Supervisor.

    Tests here.

Tu, 13 June 2017 | v7.1.1

Fix that.

Mo, 12 June 2017 | v7.1.0

Fix that.

Su, 11 June 2017 | v7.0.5

Iris now supports static paths and dynamic paths for the same path prefix with zero performance cost:

app.Get("/profile/{id:int}", handler) and app.Get("/profile/create", createHandler) are not in conflict anymore.

The rest of the special Iris' routing features, including static & wildcard subdomains are still work like a charm.

This was one of the most popular community's feature requests. Click here to see a trivial example.

Sa, 10 June 2017 | v7.0.4

  • Simplify and add a test for the basicauth middleware, no need to be
    stored inside the Context anymore, developers can get the validated user(username and password) via context.Request().BasicAuth(). basicauth.Config.ContextKey was removed, just remove that field from your configuration, it's useless now.

Sa, 10 June 2017 | v7.0.3

  • New context.Session().PeekFlash("key") added, unlike GetFlash this will return the flash value but keep the message valid for the next requests too.
  • Complete the httptest example.
  • Fix the (marked as deprecated) ListenLETSENCRYPT function.
  • Upgrade the iris-contrib/middleware including JWT, CORS and Secure handlers.
  • Add OAuth2 example -- showcases the third-party package goth integration with Iris.

Community

Th, 08 June 2017 | v7.0.2

  • Able to set immutable data on sessions and context's storage. Aligned to fix an issue on slices and maps as reported here.

We, 07 June 2017 | v7.0.1

  • Proof of concept of an internal release generator, navigate here to read more.
  • Remove tray icon "feature", click here to learn why.

Sa, 03 June 2017

After 2+ months of hard work and collaborations, Iris version 7 was published earlier today.

If you're new to Iris you don't have to read all these, just navigate to the updated examples and you should be fine:)

Note that this section will not
cover the internal changes, the difference is so big that anybody can see them with a glimpse, even the code structure itself.

Changes from v6

The whole framework was re-written from zero but I tried to keep the most common public API that iris developers use.

Vendoring /w update

The previous vendor action for v6 was done by-hand, now I'm using the go dep tool, I had to do
some small steps:

  • remove files like testdata to reduce the folder size
  • rollback some of the "golang/x/net/ipv4" and "ipv6" source files because they are downloaded to their latest versions
    by go dep, but they had lines with the typealias feature, which is not ready by current golang version (it will be on August)
  • fix "cannot use internal package" at golang/x/net/ipv4 and ipv6 packages
    • rename the interal folder to was-internal, everywhere and fix its references.
  • fix "main redeclared in this block"
    • remove all examples folders.
  • remove main.go files on jsondiff lib, used by gavv/httpexpect, produces errors on test -v ./... while jd and jp folders are not used at all.

The go dep tool does what is says, as expected, don't be afraid of it now.
I am totally recommending this tool for package authors, even if it's in its alpha state.
I remember when Iris was in its alpha state and it had 4k stars on its first weeks/or month and that helped me a lot to fix reported bugs by users and make the framework even better, so give love to go dep from today!

General

  • Several enhancements for the typescript transpiler, view engine, websocket server and sessions manager
  • All Listen methods replaced with a single Run method, see here
  • Configuration, easier to modify the defaults, see here
  • HandlerFunc removed, just Handler of func(context.Context) where context.Context derives from import "github.com/kataras/iris/context" (NEW: this import path is optional, use iris.Context if you've installed Go 1.9)
    • Simplify API, i.e: instead of Handle,HandleFunc,Use,UseFunc,Done,DoneFunc,UseGlobal,UseGlobalFunc use Handle,Use,Done,UseGlobal.
  • Response time decreased even more (9-35%, depends on the application)
  • The Adaptors idea replaced with a more structural design pattern, but you have to apply these changes:
    • app.Adapt(view.HTML/Pug/Amber/Django/Handlebars...) -> app.AttachView(view.HTML/Pug/Amber/Django/Handlebars...)
    • app.Adapt(sessions.New(...)) -> app.AttachSessionManager(sessions.New(...))
    • app.Adapt(iris.LoggerPolicy(...)) -> app.AttachLogger(io.Writer)
    • app.Adapt(iris.RenderPolicy(...)) -> removed and replaced with the ability to replace the whole context with a custom one or override some methods of it, see below.

Routing

  • Remove of multiple routers, now we have the fresh Iris router which is based on top of the julien's httprouter.

    Update 11 June 2017: As of 7.0.5 this is changed, read here.

  • Subdomains routing algorithm has been improved.
  • Iris router is using a custom interpreter with parser and path evaluator to achieve the best expressiveness, with zero performance loss, you ever seen so far, i.e:
    • app.Get("/", "/users/{userid:int min(1)}", handler),
      • {username:string} or just {username}
      • {asset:path},
      • {firstname:alphabetical},
      • {requestfile:file} ,
      • {mylowercaseParam regexp([a-z]+)}.
      • The previous syntax of :param and *param still working as expected. Previous rules for paths confliction remain as they were.
        • Also, path parameter names should be only alphabetical now, numbers and symbols are not allowed (for your own good, I have seen a lot the last year...).

Click here for details.

It was my first attempt/experience on the interpreters field, so be good with it :)

Context

  • iris.Context pointer replaced with context.Context interface as we already mention
    • in order to be able to use a custom context and/or catch lifetime like BeginRequest and EndRequest from context itself, see below
  • context.JSON, context.JSONP, context.XML, context.Markdown, context.HTML work faster
  • context.Render("filename.ext", bindingViewData{}, options) -> context.View("filename.ext")
    • View renders only templates, it will not try to search if you have a restful renderer adapted, because, now, you can do it via method overriding using a custom Context.
    • Able to set context.ViewData and context.ViewLayout via middleware when executing a template.
  • context.SetStatusCode(statusCode) -> context.StatusCode(statusCode)
    • which is equivalent with the old EmitError too:
      • if status code >=400 given can automatically fire a custom http error handler if response wasn't written already.
    • context.StatusCode() -> context.GetStatusCode()
    • app.OnError -> app.OnErrorCode
    • Errors per party are removed by-default, you can just use one global error handler with logic like "if path starts with 'prefix' fire this error handler, else...".
  • Easy way to change Iris' default Context with a custom one, see here
  • context.ResponseWriter().SetBeforeFlush(...) works for Flush and HTTP/2 Push, respectfully
  • Several improvements under the Request transactions
  • Remember that you had to set a status code on each of the render-relative methods? Now it's not required, it just renders
    with the status code that user gave with context.StatusCode or with 200 OK, i.e:
    -context.JSON(iris.StatusOK, myJSON{}) -> context.JSON(myJSON{}).
    • Each one of the context's render methods has optional per-call settings,
    • the new API is even more easier to read, understand and use.

Server

  • Able to set custom underline *http.Server(s) with new Host (aka Server Supervisor) feature
    • Done and Err channels to catch shutdown or any errors on custom hosts,
    • Schedule custom tasks(with cancelation) when server is running, see here
  • Interrupt handler task for gracefully shutdown (when CTRL/CMD+C) are enabled by-default, you can disable its via configuration: app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler)

Future plans

  • Future Go1.9's ServeTLS is ready when 1.9 released
  • Future Go1.9's typealias feature is ready when 1.9 released, i.e context.Context -> iris.Context just one import path instead of todays' two.

v8.5.7

@kataras kataras released this Nov 7, 2017 · 216 commits to master since this release

FAQ

Looking for free and real-time support?

https://github.com/kataras/iris/issues
https://chat.iris-go.com

Looking for previous versions?

https://github.com/kataras/iris/releases

Iris uses the vendor directory feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes.

Tu, 07 November 2017 | v8.5.7

Nothing crazy here, just one addition which may help some people;

Able to share configuration between multiple Iris instances based on the $home_path+iris.yml configuration file with the new iris.WithGlobalConfiguration configurator*.

Example:

package main
import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Get("/", func(ctx iris.Context) {
        ctx.HTML("<b>Hello!</b>")
    })
    // [...]

    // Good when you share configuration between multiple iris instances.
    // This configuration file lives in your $HOME/iris.yml for unix hosts
    // or %HOMEDRIVE%+%HOMEPATH%/iris.yml for windows hosts, and you can modify it.
    app.Run(iris.Addr(":8080"), iris.WithGlobalConfiguration)
    // or before run:
    // app.Configure(iris.WithGlobalConfiguration)
    // app.Run(iris.Addr(":8080"))
}

Su, 05 November 2017 | v8.5.6

TODO;

  • give the ability to customize the mvc path-method-and path parameters mapping,
  • make a github bot which will post the monthly usage and even earnings statistics in a public github markdown file, hope that users will love that type of transparency we will introduce here.

Th, 02 November 2017 | v8.5.5

  • fix audio/mpeg3 does not appear to be a valid registered mime type#798 reported by @kryptodev,
  • improve the updater's performance and moved that into the framework itself,
    • ask for authentication only when a new version is released.
  • sessiondb's .Async functions do nothing now, all session databases(back-end persistence storage) should run in-sync, @speedwheel helped to find a misbehavior because of that setting,
  • the configuration now has json fields tag like yaml and toml did in order to be able to be fetched from a json file directly using the encoding/json package,
  • fix the context#GetFloat64,
  • we are on opencollective and sponsored by codesponsor now.

TODO;

  • give the ability to customize the mvc path-method-and path parameters mapping,
  • make a github bot which will post the monthly usage and even earnings statistics in a public github markdown file, hope that users will love that type of transparency we will introduce here.

Th, 26 October 2017 | v8.5.4

This version is part of the releases.

Version Updater

Not any new features or fixes (all reported bugs are fixed) in this version, just a tiny improvement.

More friendly version checker!

Remember: If you don't want to keep the version checker and you're pretty sure that you will be able to keep your server up-to-date manually, then you can disable the auto updater via; app.Run(..., iris.WithoutVersionChecker).

We need your help with translations into your native language

Iris needs your help, please think about contributing to the translation of the README and https://iris-go.com, you will be rewarded.

Instructions can be found at: #796

Su, 22 October 2017 | v8.5.3

🎗️ People that you should follow

Help this project to continue deliver awesome and unique features with the higher code quality as possible by donating any amount via PayPal or BTC!

Name Amount Membership
Juan Sebastián Suárez Valencia 20 EUR Bronze
Bob Lee 20 EUR Bronze
Celso Luiz 50 EUR Silver
Ankur Srivastava 20 EUR Bronze
Damon Zhao 20 EUR Bronze
Exponity - Tech Company 30 EUR Bronze
Thomas Fritz 25 EUR Bronze
Thanos V. 20 EUR Bronze
George Opritescu 20 EUR Bronze
Lex Tang 20 EUR Bronze
Bill Q. 600 EUR Gold
Conrad Steenberg 25 EUR Bronze

Th, 12 October 2017 | v8.5.2

This version is part of the releases.

MVC

Add bool as a supported return value, if false then skips everything else and fires 404 not found.

New example which covers the Service and Repository layers side-by-side with the MVC Architectural pattern, clean and simple: _examples/mvc/overview.

Websocket

Fix(?) #782 by @jerson with PR: #783.

Minor

Add some minor comments for the view/django's origin type getters-- as pushed at PR: #765.

sessions/sessiondb/badger vendored with: e7517ec.

Tu, 10 October 2017 | v8.5.1

MVC

  • fix any manual or before middleware's ctx.ViewData(key, value) gets overridden by setting mvc.Controller.Data or return mvc.View {Data: ...}. See the test case.

Mo, 09 October 2017 | v8.5.0

MVC

Great news for our MVC Fans or if you're not you may want to use that powerful feature today, because of the smart coding and decisions the performance is quite the same to the pure handlers, see _benchmarks.

A Controller's field that is an interface can now be binded to any type that implements that interface.

Ability to send HTTP responses based on the Controller's method function's output values, see below;

Iris now gives you the ability to render a response based on the output values returned from the controller's method functions!

You can return any value of any type from a method function
and it will be sent to the client as expected.

  • if string then it's the body.
  • if string is the second output argument then it's the content type.
  • if int then it's the status code.
  • if error and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead.
  • if (int, error) and error is not nil then the response result will be the error's text with the status code as int.
  • if custom struct or interface{} or slice or map then it will be rendered as json, unless a string content type is following.
  • if mvc.Result then it executes its Dispatch function, so good design patters can be used to split the model's logic where needed.

The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before;

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/middleware/basicauth"
    "github.com/kataras/iris/mvc"
)

// Movie is our sample data structure.
type Movie struct {
    Name   string `json:"name"`
    Year   int    `json:"year"`
    Genre  string `json:"genre"`
    Poster string `json:"poster"`
}

// movies contains our imaginary data source.
var movies = []Movie{
    {
        Name:   "Casablanca",
        Year:   1942,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg",
    },
    {
        Name:   "Gone with the Wind",
        Year:   1939,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg",
    },
    {
        Name:   "Citizen Kane",
        Year:   1941,
        Genre:  "Mystery",
        Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg",
    },
    {
        Name:   "The Wizard of Oz",
        Year:   1939,
        Genre:  "Fantasy",
        Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg",
    },
}


var basicAuth = basicauth.New(basicauth.Config{
    Users: map[string]string{
        "admin": "password",
    },
})


func main() {
    app := iris.New()

    app.Use(basicAuth)

    app.Controller("/movies", new(MoviesController))

    app.Run(iris.Addr(":8080"))
}

// MoviesController is our /movies controller.
type MoviesController struct {
    // mvc.C is just a lightweight lightweight alternative
    // to the "mvc.Controller" controller type,
    // use it when you don't need mvc.Controller's fields
    // (you don't need those fields when you return values from the method functions).
    mvc.C
}

// Get returns list of the movies
// Demo:
// curl -i http://localhost:8080/movies
func (c *MoviesController) Get() []Movie {
    return movies
}

// GetBy returns a movie
// Demo:
// curl -i http://localhost:8080/movies/1
func (c *MoviesController) GetBy(id int) Movie {
    return movies[id]
}

// PutBy updates a movie
// Demo:
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
func (c *MoviesController) PutBy(id int) Movie {
    // get the movie
    m := movies[id]

    // get the request data for poster and genre
    file, info, err := c.Ctx.FormFile("poster")
    if err != nil {
        c.Ctx.StatusCode(iris.StatusInternalServerError)
        return Movie{}
    }
    file.Close()            // we don't need the file
    poster := info.Filename // imagine that as the url of the uploaded file...
    genre := c.Ctx.FormValue("genre")

    // update the poster
    m.Poster = poster
    m.Genre = genre
    movies[id] = m

    return m
}

// DeleteBy deletes a movie
// Demo:
// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1
func (c *MoviesController) DeleteBy(id int) iris.Map {
    // delete the entry from the movies slice
    deleted := movies[id].Name
    movies = append(movies[:id], movies[id+1:]...)
    // and return the deleted movie's name
    return iris.Map{"deleted": deleted}
}

Another good example with a typical folder structure, that many developers are used to work, is located at the new README.md under the Quick MVC Tutorial #3 section.

Fr, 06 October 2017 | v8.4.5

  • Badger team added support for transactions yesterday, therefore the badger session database is updated via 0b48927.
  • MVC: Support more than one path parameters with a single By, when the By keyword is the last word and the func's input arguments are more than one i.e GetBy(name string, age int), note that you can still use the older way of doing this; GetByBy(string, int). It's an enhancement of the #751 feature request.
  • MVC: Give controllers the ability to auto-initialize themselves by OnActivate func derives from the new ActivateListener interface, this can be used to perform any custom actions when the app registers the supported Controllers. See mvc/session_controller.go for a good use case.
  • errors.Reporter.AddErr returns true if the error is added to the stack, otherwise false.
  • @ZaniaDeveloper fixed #778 with PR: #779.
  • Add StatusSeeOther at mvc login example for Redirection, reported by @motecshine at #777.
  • Fix DisableVersionChecker configuration field is not being passed correctly when it was true via app.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...}) call.

Su, 01 October 2017 | v8.4.4

  • Fix #762 reported by @xkylsoft
  • Fix #771 reported by @cdren
  • Improvements to the memstore's GetInt, GetInt64, GetFloat64, GetBool and remove the golang/net/context's interface completion from Context, read the changes for more
  • Add two examples for folder structuring as requested at #748
  • Add node.js express benchmarks similar to iris and netcore

We, 27 September 2017 | v8.4.3

Fr, 15 September 2017 | v8.4.2

MVC

Support more than one dynamic method function receivers.

package main

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Controller("/user", new(UserController))
    app.Run(iris.Addr("localhost:8080"))
}

type UserController struct { iris.Controller }

// Maps to GET /user
// Request example: http://localhost:8080/user
// as usual.
func (c *UserController) Get() {
    c.Text = "hello from /user"
}

// Maps to GET /user/{paramfirst:long}
// Request example: http://localhost:8080/user/42
// as usual.
func (c *UserController) GetBy(userID int64) {
    c.Ctx.Writef("hello user with id: %d", userID)
}

// NEW:
// Maps to GET /user/{paramfirst:long}/business/{paramsecond:long}
// Request example: http://localhost:8080/user/42/business/93
func (c *UserController) GetByBusinessBy(userID int64, businessID int64) {
    c.Ctx.Writef("fetch a business id: %d that user with id: %d owns, may make your db query faster",
    businessID, userID)
}

Th, 07 September 2017 | v8.4.1

Routing

Add a macro type for booleans: app.Get("/mypath/{paramName:boolean}", myHandler).

+------------------------+
| {param:boolean}        |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"

Add context.Params().GetBool(paramName string) (bool, error) respectfully.

app := iris.New()
app.Get("/mypath/{has:boolean}", func(ctx iris.Context) { // <--
    // boolean first return value
    // error as second return value
    //
    // error will be always nil here because
    // we use the {has:boolean} so router
    // makes sure that the parameter is a boolean
    // otherwise it will return a 404 not found http error code
    // skipping the call of this handler.
    has, _ := ctx.Params().GetBool("has") // <--
    if has {
        ctx.HTML("<strong>it's true</strong>")
    }else {
        ctx.HTML("<strong>it's false</string>")
    }
})
// [...]

MVC

Support for boolean method receivers, i.e GetBy(bool), PostBy(bool)....

app := iris.New()

app.Controller("/equality", new(Controller))
type Controller struct {
    iris.Controller
}

// handles the "/equality" path.
func (c *Controller) Get() {

}

// registers and handles the path: "/equality/{param:boolean}".
func (c *Controller) GetBy(is bool) { // <--
    // [...]
}

Supported types for method functions receivers are: int, int64, bool and string.

Su, 27 August 2017 | v8.4.0

Miscellaneous

Router

Add a new macro type for path parameters, long, it's the go type int64.

app.Get("/user/{id:long}", func(ctx context.Context) {
	userID, _ := ctx.Params().GetInt64("id")
})

MVC

The ability to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that after a go get -u github.com/kataras/iris you will be able to use things like these:

If app.Controller("/user", new(user.Controller))

  • func(*Controller) Get() - GET:/user , as usual.
  • func(*Controller) Post() - POST:/user, as usual.
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

If app.Controller("/profile", new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

If app.Controller("/assets", new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

Example can be found at: _examples/mvc/login/user/controller.go.

Pretty awesome, right?

We, 23 August 2017 | v8.3.4

Give read access to the current request context's route, a feature that many of you asked a lot.

func(ctx context.Context) {
	_ = ctx.GetCurrentRoute().Name()
	//					.Method() returns string, same as ctx.Method().
	//					.Subdomain() returns string, the registered subdomain.
	//					.Path() returns string, the registered path.
	//					.IsOnline() returns boolean.
}
type MyController struct {
	mvc.Controller
}

func (c *MyController) Get(){
	_ = c.Route().Name() // same as `c.Ctx.GetCurrentRoute().Name()`.
	// [...]
}

Updated: 24 August 2017

This evening, on the next version 8.3.5:

Able to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that in the future you will be able to use something like these:

If app.Controller("/user", new(user.Controller))

  • func(c *Controller) Get() - GET:/user , as usual.
  • func(c *Controller) Post() - POST:/user, as usual.
  • func(c *Controller) GetLogin() - GET:/user/login
  • func(c *Controller) PostLogin() - POST:/user/login
  • func(c *Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(c *Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(c *Controller) GetBy() - GET:/user/{param}
  • func(c *Controller) GetByName(name string) - GET:/user/{name}
  • func(c *Controller) PostByName(name string) - POST:/user/{name}
  • func(c *Controller) GetByID(id int64 || int) - GET:/user/{id:int}
  • func(c *Controller) PostByID(id int64 || int) - POST:/user/{id:int}

Watch and stay tuned my friends.

We, 23 August 2017 | v8.3.3

Better debug messages when using MVC.

Add support for recursively binding and custom controllers embedded to other custom controller, that's the new feature. That simply means that Iris users are able to use "shared" controllers everywhere; when binding, using models, get/set persistence data, adding middleware, intercept request flow.

This will help web authors to split the logic at different controllers. Those controllers can be also used as "standalone" to serve a page somewhere else in the application as well.

My personal advice to you is to always organize and split your code nicely and wisely in order to avoid using such as an advanced MVC feature, at least any time soon.

I'm aware that this is not always an easy task to do, therefore is here if you ever need it :)

A ridiculous simple example of this feature can be found at the mvc/controller_test.go file.

Tu, 22 August 2017 | v8.3.2

MVC

When one or more values of handler type (func(ctx context.Context)) are passed
right to the controller initialization then they will be recognised and act as middleware(s)
that ran even before the controller activation, there is no reason to load
the whole controller if the main handler or its BeginRequest are not "allowed" to be executed.

Example Code

func checkLogin(ctx context.Context) {
	if !myCustomAuthMethodPassed {
		// [set a status or redirect, you know what to do]
		ctx.StatusCode(iris.StatusForbidden)
		return
	}

	// [continue to the next handler, at this example is our controller itself]
	ctx.Next()
}

// [...]
app.Controller(new(ProfileController), checkLogin)
// [...]

Usage of these kind of MVC features could be found at the mvc/controller_test.go file.

Other minor enhancements

  • fix issue #726*
  • fix redis sessiondb expiration*
  • update recursively when new version is available*
  • some minor session enhancements*

Sa, 19 August 2017 | v8.3.1

First of all I want to thank you for the 100% green feedback you gratefully sent me you about
my latest article Go vs .NET Core in terms of HTTP performance, published at medium's hackernoon.com and dev.to. I really appreciate it💓

No API Changes.

However two more methods added to the Controller.

  • RelPath() string, returns the relative path based on the controller's name and the request path.
  • RelTmpl() string, returns the relative template directory based on the controller's name.

These are useful when dealing with big controllers, they help you to keep align with any
future changes inside your application.

Want to learn more about these functions? Go to the mvc/controller_test.go file and scroll to the bottom!

Fr, 18 August 2017 | v8.3.0

Good news for devs that are used to write their web apps using the MVC architecture pattern.

Implement a whole new mvc package with additional support for models and easy binding.

@kataras started to develop that feature by version 8.2.5, back then it didn't seem
to be a large feature and maybe a game-changer, so it lived inside the kataras/iris/core/router/controller.go file.
However with this version, so many things are implemented for the MVC and we needed a new whole package,
this new package is the kataras/iris/mvc, but if you used go 1.9 to build then you don't have to do any refactor, you could use the iris.Controller type alias.

People who used the mvc from its baby steps(v8.2.5) the only syntactic change you'll have to do is to rename the router.Controller to mvc.Controller:

Before:

import "github.com/kataras/iris/core/router"
type MyController struct {
    router.Controller
}

Now:

import "github.com/kataras/iris/mvc"
type MyController struct {
    mvc.Controller
    // if you build with go1.9 you can omit the import of mvc package
    // and just use `iris.Controller` instead.
}

MVC (Model View Controller)

From version 8.3 and after Iris has first-class support for the MVC pattern, you'll not find
these stuff anywhere else in the Go world.

Example Code

package main

import (
	"sync"

	"github.com/kataras/iris"
	"github.com/kataras/iris/mvc"
)

func main() {
	app := iris.New()
	app.RegisterView(iris.HTML("./views", ".html"))

	// when we have a path separated by spaces
	// then the Controller is registered to all of them one by one.
	//
	// myDB is binded to the controller's `*DB` field: use only structs and pointers.
	app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
		new(ProfileController), myDB) // IMPORTANT

	app.Run(iris.Addr(":8080"))
}

// UserModel our example model which will render on the template.
type UserModel struct {
	ID       int64
	Username string
}

// DB is our example database.
type DB struct {
	usersTable map[int64]UserModel
	mu         sync.RWMutex
}

// GetUserByID imaginary database lookup based on user id.
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
	db.mu.RLock()
	u, found = db.usersTable[id]
	db.mu.RUnlock()
	return
}

var myDB = &DB{
	usersTable: map[int64]UserModel{
		1:  {1, "kataras"},
		2:  {2, "makis"},
		42: {42, "jdoe"},
	},
}

// ProfileController our example user controller which controls
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
type ProfileController struct {
	mvc.Controller // IMPORTANT

	User UserModel `iris:"model"`
	// we will bind it but you can also tag it with`iris:"persistence"`
	// and init the controller with manual &PorifleController{DB: myDB}.
	DB *DB
}

// Get method handles all "GET" HTTP Method requests of the controller's paths.
func (pc *ProfileController) Get() { // IMPORTANT
	path := pc.Path

	// requested: /profile path
	if path == "/profile" {
		pc.Tmpl = "profile/index.html"
		return
	}
	// requested: /profile/browse
	// this exists only to proof the concept of changing the path:
	// it will result to a redirection.
	if path == "/profile/browse" {
		pc.Path = "/profile"
		return
	}

	// requested: /profile/me path
	if path == "/profile/me" {
		pc.Tmpl = "profile/me.html"
		return
	}

	// requested: /profile/$ID
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound
		pc.Tmpl = "profile/notfound.html"
		pc.Data["ID"] = id
		return
	}

	pc.Tmpl = "profile/profile.html"
	pc.User = user
}


/*
func (pc *ProfileController) Post() {}
func (pc *ProfileController) Put() {}
func (pc *ProfileController) Delete() {}
func (pc *ProfileController) Connect() {}
func (pc *ProfileController) Head() {}
func (pc *ProfileController) Patch() {}
func (pc *ProfileController) Options() {}
func (pc *ProfileController) Trace() {}
*/

/*
func (pc *ProfileController) All() {}
//        OR
func (pc *ProfileController) Any() {}
*/

Iris web framework supports Request data, Models, Persistence Data and Binding
with the fastest possible execution.

Characteristics

All HTTP Methods are supported, for example if want to serve GET
then the controller should have a function named Get(),
you can define more than one method function to serve in the same Controller struct.

Persistence data inside your Controller struct (share data between requests)
via iris:"persistence" tag right to the field or Bind using app.Controller("/" , new(myController), theBindValue).

Models inside your Controller struct (set-ed at the Method function and rendered by the View)
via iris:"model" tag right to the field, i.e User UserModel `iris:"model" name:"user"` view will recognise it as {{.user}}.
If name tag is missing then it takes the field's name, in this case the "User".

Access to the request path and its parameters via the Path and Params fields.

Access to the template file that should be rendered via the Tmpl field.

Access to the template data that should be rendered inside
the template file via Data field.

Access to the template layout via the Layout field.

Access to the low-level context.Context via the Ctx field.

Get the relative request path by using the controller's name via RelPath().

Get the relative template path directory by using the controller's name via RelTmpl().

Flow as you used to, Controllers can be registered to any Party,
including Subdomains, the Party's begin and done handlers work as expected.

Optional BeginRequest(ctx) function to perform any initialization before the method execution,
useful to call middlewares or when many methods use the same collection of data.

Optional EndRequest(ctx) function to perform any finalization after any method executed.

Inheritance, recursively, see for example our mvc.SessionController, it has the mvc.Controller as an embedded field
and it adds its logic to its BeginRequest, here.

Read access to the current route via the Route field.

Using Iris MVC for code reuse

By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.

If you're new to back-end web development read about the MVC architectural pattern first, a good start is that wikipedia article.

Follow the examples below,

https://github.com/kataras/iris/tree/master/_examples/#mvc

Bugs

Fix #723 reported by @speedwheel.

Mo, 14 August 2017 | v8.2.6

Able to call done/end handlers inside a Controller, via optional EndRequest(ctx context.Context) function inside the controller struct.

// it's called after t.Get()/Post()/Put()/Delete()/Connect()/Head()/Patch()/Options()/Trace().
func (t *testControllerEndRequestFunc) EndRequest(ctx context.Context) {
    // 2.
    // [your code goes here...]
}

// will handle "GET" request HTTP method only.
func (t *testControllerEndRequestFunc) Get() {
    // 1.
    // [your code goes here...]
}

Look at the v8.2.5 changelog to learn more about the new Iris Controllers feature.

Su, 13 August 2017 | v8.2.5

Good news for devs that are used to write their web apps using the MVC-style app architecture.

Yesterday I wrote a tutorial on how you can transform your raw Handlers to Controllers using the existing tools only (Iris is the most modular web framework out there, we all have no doubt about this).

Today, I did implement the Controller idea as built'n feature inside Iris.
Our Controller supports many things among them are:

  • all HTTP Methods are supported, for example if want to serve GET then the controller should have a function named Get(), you can define more than one method function to serve in the same Controller struct
  • persistence data inside your Controller struct (share data between requests) via iris:"persistence" tag right to the field
  • optional BeginRequest(ctx) function to perform any initialization before the methods, useful to call middlewares or when many methods use the same collection of data
  • optional EndRequest(ctx) function to perform any finalization after the methods executed
  • access to the request path parameters via the Params field
  • access to the template file that should be rendered via the Tmpl field
  • access to the template data that should be rendered inside the template file via Data field
  • access to the template layout via the Layout field
  • access to the low-level context.Context via the Ctx field
  • flow as you used to, Controllers can be registered to any Party, including Subdomains, the Party's begin and done handlers work as expected.

It's very easy to get started, the only function you need to call instead of app.Get/Post/Put/Delete/Connect/Head/Patch/Options/Trace is the app.Controller.

Example Code:

// file: main.go

package main

import (
    "github.com/kataras/iris"

    "controllers"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    app.Controller("/", new(controllers.Index))

    // http://localhost:8080/
    app.Run(iris.Addr(":8080"))
}
// file: controllers/index.go

package controllers

import (
    "github.com/kataras/iris/core/router"
)

// Index is our index example controller.
type Index struct {
    mvc.Controller
    // if you're using go1.9: 
    // you can omit the /core/router import statement
    // and just use the `iris.Controller` instead.
}

// will handle GET method on http://localhost:8080/
func (c *Index) Get() {
    c.Tmpl = "index.html"
    c.Data["title"] = "Index page"
    c.Data["message"] = "Hello world!"
}

// will handle POST method on http://localhost:8080/
func (c *Index) Post() {}

Tip: declare a func(c *Index) All() {} or Any() to register all HTTP Methods.

A full example can be found at the _examples/mvc folder.

Sa, 12 August 2017 | v8.2.4

No API Changes.

Fix #717, users are welcomed to follow the thread for any questions or reports about Gzip and Static Files Handlers only.

Th, 10 August 2017 | v8.2.3

No API Changes.

Fix #714

Continue to v8.2.2 for more...

Th, 10 August 2017 | v8.2.2

No API Changes.

  • Implement Google reCAPTCHA middleware, example here
  • Fix kataras/golog prints with colors on windows server 2012 while it shouldn't because its command line tool does not support 256bit colors
  • Improve the updater by a custom self-updated back-end version checker, can be disabled by:
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)

Or

app.Configure(iris.WithoutVersionChecker)

Or

app.Configure(iris.WithConfiguration(iris.Configuration{DisableVersionChecker:true}))

Tu, 08 August 2017 | v8.2.1

No API Changes. Great news for the unique iris sessions library, once again.

NEW: LevelDB-based session database implemented, example here.

Redis-based sessiondb has no longer the MaxAgeSeconds config field,
this is passed automatically by the session manager, now.

All sessions databases have an Async(bool) function, if turned on
then all synchronization between the memory store and the back-end database will happen
inside different go routines. By-default async is false but it's recommended to turn it on, it will make sessions to be stored faster, at most.

All reported issues have been fixed, the API is simplified by v8.2.0 so everyone can
create and use any back-end storage for application's sessions persistence.

Mo, 07 August 2017 | v8.2.0

No Common-API Changes.

Good news for iris sessions back-end databases users.

Info for session database authors Session Database API Changed to:
type Database interface {
	Load(sid string) RemoteStore
	Sync(p SyncPayload)
}

// SyncPayload reports the state of the session inside a database sync action.
type SyncPayload struct {
	SessionID string

	Action Action
	// on insert it contains the new key and the value
	// on update it contains the existing key and the new value
	// on delete it contains the key (the value is nil)
	// on clear it contains nothing (empty key, value is nil)
	// on destroy it contains nothing (empty key, value is nil)
	Value memstore.Entry
	// Store contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Store RemoteStore
}


// RemoteStore is a helper which is a wrapper
// for the store, it can be used as the session "table" which will be
// saved to the session database.
type RemoteStore struct {
	// Values contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Values memstore.Store
	// on insert it contains the expiration datetime
	// on update it contains the new expiration datetime(if updated or the old one)
	// on delete it will be zero
	// on clear it will be zero
	// on destroy it will be zero
	Lifetime LifeTime
}

Read more at sessions/database.go, view how three built'n session databases are being implemented here.

All sessions databases are updated and they performant even faster than before.

  • NEW raw file-based session database implemented, example here
  • NEW boltdb-based session database implemented, example here (recommended as it's safer and faster)
  • redis sessiondb updated to the latest api

Under the cover, session database works entirely differently than before but nothing changed from the user's perspective, so upgrade with go get -u github.com/kataras/iris and sleep well.

Tu, 01 August 2017 | v8.1.3

  • Add Option function to the html view engine: #694
  • Fix sessions backend databases restore expiration: #692 by @corebreaker
  • Add PartyFunc, same as Party but receives a function with the sub router as its argument instead [GO1.9 Users-ONLY]

Mo, 31 July 2017 | v8.1.2

Add a ConfigureHost function as an alternative way to customize the hosts via host.Configurator.
The first way was to pass host.Configurator as optional arguments on iris.Runners built'n functions (iris#Server, iris#Listener, iris#Addr, iris#TLS, iris#AutoTLS), example of this can be found there.

Example Code:

package main

import (
	stdContext "context"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/host"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx context.Context) {
		ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
	})

    app.ConfigureHost(configureHost) // or pass "configureHost" as `app.Addr` argument, same result.

	app.Logger().Info("Wait 10 seconds and check your terminal again")
	// simulate a shutdown action here...
	go func() {
		<-time.After(10 * time.Second)
		timeout := 5 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		// close all hosts, this will notify the callback we had register
		// inside the `configureHost` func.
		app.Shutdown(ctx)
	}()

	// http://localhost:8080
	// wait 10 seconds and check your terminal.
	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func configureHost(su *host.Supervisor) {
	// here we have full access to the host that will be created
	// inside the `app.Run` or `app.NewHost` function .
	//
	// we're registering a shutdown "event" callback here:
	su.RegisterOnShutdown(func() {
		println("server is closed")
	})
	// su.RegisterOnError
	// su.RegisterOnServe
}

Su, 30 July 2017

Greetings my friends, nothing special today, no version number yet.

We just improve the, external, Iris Logging library and the Columns config field from middleware/logger defaults to false now. Upgrade with go get -u github.com/kataras/iris and have fun!

Sa, 29 July 2017 | v8.1.1

No breaking changes, just an addition to make your life easier.

This feature has been implemented after @corebreaker 's request, posted at: #688. He was also tried to fix that by a PR, we thanks him but the problem with that PR was the duplication and the separation of concepts, however we thanks him for pushing for a solution. The current feature's implementation gives a permant solution to host supervisor access issues.

Optional host configurators added to all common serve and listen functions.

Below you'll find how to gain access to the host, the second way is the new feature.

Hosts

Access to all hosts that serve your application can be provided by
the Application#Hosts field, after the Run method.

But the most common scenario is that you may need access to the host before the Run method,
there are two ways of gain access to the host supervisor, read below.

First way is to use the app.NewHost to create a new host
and use one of its Serve or Listen functions
to start the application via the iris#Raw Runner.
Note that this way needs an extra import of the net/http package.

Example Code:

h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){
    println("server was closed!")
})

app.Run(iris.Raw(h.ListenAndServe))

Second, and probably easier way is to use the host.Configurator.

Note that this method requires an extra import statement of
"github.com/kataras/iris/core/host" when using go < 1.9,
if you're targeting on go1.9 then you can use the iris#Supervisor
and omit the extra host import.

All common Runners we saw earlier (iris#Addr, iris#Listener, iris#Server, iris#TLS, iris#AutoTLS)
accept a variadic argument of host.Configurator, there are just func(*host.Supervisor).
Therefore the Application gives you the rights to modify the auto-created host supervisor through these.

Example Code:

package main

import (
    stdContext "context"
    "time"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
    "github.com/kataras/iris/core/host"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
        ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
    })

    app.Logger().Info("Wait 10 seconds and check your terminal again")
    // simulate a shutdown action here...
    go func() {
        <-time.After(10 * time.Second)
        timeout := 5 * time.Second
        ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
        defer cancel()
        // close all hosts, this will notify the callback we had register
        // inside the `configureHost` func.
        app.Shutdown(ctx)
    }()

    // start the server as usual, the only difference is that
    // we're adding a second (optional) function
    // to configure the just-created host supervisor.
    //
    // http://localhost:8080
    // wait 10 seconds and check your terminal.
    app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed))

}

func configureHost(su *host.Supervisor) {
    // here we have full access to the host that will be created
    // inside the `Run` function.
    //
    // we register a shutdown "event" callback
    su.RegisterOnShutdown(func() {
        println("server is closed")
    })
    // su.RegisterOnError
    // su.RegisterOnServe
}

Read more about listening and gracefully shutdown by navigating to: https://github.com/kataras/iris/tree/master/_examples/#http-listening

We, 26 July 2017 | v8.1.0

The app.Logger() *logrus.Logger was replaced with a custom implementation [golog], it's compatible with the logrus package and other open-source golang loggers as well, because of that: #680 (comment).

The API didn't change much except these:

  • the new implementation does not recognise Fatal and Panic because, actually, iris never panics
  • the old app.Logger().Out = io.Writer should be written as app.Logger().SetOutput(io.Writer)

The new implementation, golog is featured, three times faster than logrus
and it completes every common usage.

Integration

I understand that many of you may use logrus outside of Iris too. To integrate an external logrus logger just
Install it-- all print operations will be handled by the provided logrus instance.

import (
    "github.com/kataras/iris"
    "github.com/sirupsen/logrus"
)

package main(){
    app := iris.New()
    app.Logger().Install(logrus.StandardLogger()) // the package-level logrus instance
    // [...]
}

For more information about our new logger please navigate to: https://github.com/kataras/golog - contributions are welcomed as well!

Sa, 23 July 2017 | v8.0.7

Fix It's true that with UseGlobal the "/path1.txt" route call the middleware but cause the prepend, the order is inversed

Sa, 22 July 2017 | v8.0.5 & v8.0.6

No API Changes.

Performance

Add an experimental Configuration#EnableOptimizations option.

type Configuration {
    // [...]

    // EnableOptimization when this field is true
    // then the application tries to optimize for the best performance where is possible.
    //
    // Defaults to false.
    EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"`

    // [...]
}

Usage:

app.Run(iris.Addr(":8080"), iris.WithOptimizations)

Django view engine

@corebreaker pushed a PR to solve the Problem for {%extends%} in Django Engine with embedded files.

Logger

Remove the vendor/github.com/sirupsen/logrus folder, as a temporary solution for the #680 (comment).

Future versions

The logrus will be replaced with a custom implementation, because of that: #680 (comment).

As far as we know, @kataras is working on this new implementation, see here,
which will be compatible with the logrus package and other open-source golang loggers as well.

Mo, 17 July 2017 | v8.0.4

No API changes.

HTTP Errors

Fix a rare behavior: error handlers are not executed correctly
when a before-handler by-passes the order of execution, relative to the previous feature.

Request Logger

Add Configuration#MessageContextKey. Example can be found at _examples/http_request/request-logger/main.go.

Su, 16 July 2017 | v8.0.3

No API changes.

Relative issues:

HTTP Errors

Able to register a chain of Handlers (and middleware with ctx.Next() support like routes) for a specific error code, read more at issues/674. Usage example can be found at _examples/http_request/request-logger/main.go.

New function to register a Handler or a chain of Handlers for all official http error codes, by calling the new app.OnAnyErrorCode(func(ctx context.Context){}), read more at issues/675. Usage example can be found at _examples/http_request/request-logger/main.go.

Request Logger

Add Configuration#LogFunc and Configuration#Columns fields, read more at issues/676. Example can be found at _examples/http_request/request-logger/request-logger-file/main.go.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Sa, 15 July 2017 | v8.0.2

Okay my friends, this is a good time to upgrade, I did implement a feature that you were asking many times at the past.

Iris' router can now handle root-level wildcard paths app.Get("/{paramName:path}).

In case you're wondering: no it does not conflict with other static or dynamic routes, meaning that you can code something like this:

// it isn't conflicts with the rest of the static routes or dynamic routes with a path prefix.
app.Get("/{pathParamName:path}", myHandler) 

Or even like this:

package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
)

func main() {
	app := iris.New()

	// this works as expected now,
	// will handle all GET requests
	// except:
	// /                     -> because of app.Get("/", ...)
	// /other/anything/here  -> because of app.Get("/other/{paramother:path}", ...)
	// /other2/anything/here -> because of app.Get("/other2/{paramothersecond:path}", ...)
	// /other2/static        -> because of app.Get("/other2/static", ...)
	//
	// It isn't conflicts with the rest of the routes, without routing performance cost!
	//
	// i.e /something/here/that/cannot/be/found/by/other/registered/routes/order/not/matters
	app.Get("/{p:path}", h)

	// this will handle only GET /
	app.Get("/", staticPath)

	// this will handle all GET requests starting with "/other/"
	//
	// i.e /other/more/than/one/path/parts
	app.Get("/other/{paramother:path}", other)

	// this will handle all GET requests starting with "/other2/"
	// except /other2/static (because of the next static route)
	//
	// i.e /other2/more/than/one/path/parts
	app.Get("/other2/{paramothersecond:path}", other2)

	// this will handle only GET /other2/static
	app.Get("/other2/static", staticPath)

	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func h(ctx context.Context) {
	param := ctx.Params().Get("p")
	ctx.WriteString(param)
}

func other(ctx context.Context) {
	param := ctx.Params().Get("paramother")
	ctx.Writef("from other: %s", param)
}

func other2(ctx context.Context) {
	param := ctx.Params().Get("paramothersecond")
	ctx.Writef("from other2: %s", param)
}

func staticPath(ctx context.Context) {
	ctx.Writef("from the static path: %s", ctx.Path())
}

If you find any bugs with this change please send me a chat message in order to investigate it, I'm totally free at weekends.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Th, 13 July 2017 | v8.0.1

Nothing tremendous at this minor version.

We've just added a configuration field in order to ignore errors received by the Run function, see below.

Configuration#IgnoreServerErrors

type Configuration struct {
    // [...]

    // IgnoreServerErrors will cause to ignore the matched "errors"
    // from the main application's `Run` function.
    // This is a slice of string, not a slice of error
    // users can register these errors using yaml or toml configuration file
    // like the rest of the configuration fields.
    //
    // See `WithoutServerError(...)` function too.
    //
    // Defaults to an empty slice.
    IgnoreServerErrors []string `yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`

    // [...]
}

Configuration#WithoutServerError

// WithoutServerError will cause to ignore the matched "errors"
// from the main application's `Run` function.
//
// Usage:
// err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
//
// See `Configuration#IgnoreServerErrors []string` too.
WithoutServerError(errors ...error) Configurator

By default no error is being ignored, of course.

Example code:
_examples/http-listening/listen-addr/omit-server-errors

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
    	ctx.HTML("<h1>Hello World!/</h1>")
    })

    err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    if err != nil {
        // do something
    }
    // same as:
    // err := app.Run(iris.Addr(":8080"))
    // if err != nil && (err != iris.ErrServerClosed || err.Error() != iris.ErrServerClosed.Error()) {
    //     [...]
    // }
}

At first we didn't want to implement something like that because it's ridiculous easy to do it manually but a second thought came to us,
that many applications are based on configuration, therefore it would be nice to have something to ignore errors
by simply string values that can be passed to the application's configuration via toml or yaml files too.

This feature has been implemented after a request of ignoring the iris/http#ErrServerClosed from the Run function:
#668

Mo, 10 July 2017 | v8.0.0

📈 One and a half years with Iris and You...

Despite the deflamations, the clickbait articles, the removed posts of mine at reddit/r/golang, the unexpected and inadequate ban from the gophers slack room by @dlsniper alone the previous week without any reason or inform, Iris is still here and will be.

  • 7070 github stars
  • 749 github forks
  • 1m total views at its documentation
  • ~800$ at donations (there're a lot for a golang open-source project, thanks to you)
  • ~550 reported bugs fixed
  • ~30 community feature requests have been implemented

🔥 Reborn

As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore.

After a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community.

The leadership of this, open-source, repository was transferred to hiveminded, the author of iris-based get-ion/ion, he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s).

UPDATE:

I am voluntarily quiting this responsibility because I've been re-positioned as the new Lead Product Manager of the company I'm working for many years, which I accepted with honor. That's a very time consuming position I'm responsible to accomplish and deliver, therefore, I transfer all my rights back to @kataras and I resign from any copyrights over this project. My contribution clearly didn't make the difference but I owe a big "thank you" to Gerasimos for the chance he gave me and I hope the bests for him and iris. Thank you all.

These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me!

📰 Changelog

app. = app := iris.New(); app.

ctx. = func(ctx context.Context) { ctx. }

Docker

Docker and kubernetes integration showcase, see the iris-contrib/cloud-native-go repository as an example.

Logger

  • Logger which was an io.Writer was replaced with the pluggable logrus.
    • which you still attach an io.Writer with app.Logger().Out = an io.Writer.
    • iris as always logs only critical errors, you can disable them with app.Logger().Level = iris.NoLog
    • the request logger outputs the incoming requests as INFO level.

Sessions

Remove ctx.Session() and app.AttachSessionManager, devs should import and use the sessions package as standalone, it's totally optional, devs can use any other session manager too. Examples here.

Websockets

The github.com/kataras/iris/websocket package does not handle the endpoint and client side automatically anymore. Example code:

func setupWebsocket(app *iris.Application) {
    // create our echo websocket server
    ws := websocket.New(websocket.Config{
    	ReadBufferSize:  1024,
    	WriteBufferSize: 1024,
    })
    ws.OnConnection(handleConnection)
    // serve the javascript built'n client-side library,
    // see weboskcets.html script tags, this path is used.
    app.Any("/iris-ws.js", func(ctx context.Context) {
    	ctx.Write(websocket.ClientSource)
    })

    // register the server on an endpoint.
    // see the inline javascript code in the websockets.html, this endpoint is used to connect to the server.
    app.Get("/echo", ws.Handler())
}

More examples here

View

Rename app.AttachView(...) to app.RegisterView(...).

Users can omit the import of github.com/kataras/iris/view and use the github.com/kataras/iris package to
refer to the view engines, i.e: app.RegisterView(iris.HTML("./templates", ".html")) is the same as import "github.com/kataras/iris/view" [...] app.RegisterView(view.HTML("./templates" ,".html")).

Examples here

Security

At previous versions, when you called ctx.Remoteaddr() Iris could parse and return the client's IP from the "X-Real-IP", "X-Forwarded-For" headers. This was a security leak as you can imagine, because the user can modify them. So we've disabled these headers by-default and add an option to add/remove request headers that are responsible to parse and return the client's real IP.

// WithRemoteAddrHeader enables or adds a new or existing request header name
// that can be used to validate the client's real IP.
//
// Existing values are:
// "X-Real-Ip":             false,
// "X-Forwarded-For":       false,
// "CF-Connecting-IP": false
//
// Look `context.RemoteAddr()` for more.
WithRemoteAddrHeader(headerName string) Configurator // enables a header.
WithoutRemoteAddrHeader(headerName string) Configurator // disables a header.

For example, if you want to enable the "CF-Connecting-IP" header (cloudflare)
you have to add the WithRemoteAddrHeader option to the app.Run function, at the end of your program.

app.Run(iris.Addr(":8080"), iris.WithRemoteAddrHeader("CF-Connecting-IP"))
// This header name will be checked when ctx.RemoteAddr() called and if exists
// it will return the client's IP, otherwise it will return the default *http.Request's `RemoteAddr` field.

Miscellaneous

Fix typescript tools.

_examples folder has been ordered by feature and usage:
- contains tests on some examples
- new examples added, one of them shows how the reuseport feature on UNIX and BSD systems can be used to listen for incoming connections, see here

Replace supervisor's tasks with events, like RegisterOnShutdown, RegisterOnError, RegisterOnServe and fix the (unharmful) race condition when output the banner to the console. Global notifier for interrupt signals which can be disabled via app.Run([...], iris.WithoutInterruptHandler), look graceful-shutdown example for more.

More handlers are ported to Iris (they can be used as they are without iris.FromStd), these handlers can be found at iris-contrib/middleware. Feel free to put your own there.

Middleware Description Example
jwt Middleware checks for a JWT on the Authorization header on incoming requests and decodes it. iris-contrib/middleware/jwt/_example
cors HTTP Access Control. iris-contrib/middleware/cors/_example
secure Middleware that implements a few quick security wins. iris-contrib/middleware/secure/_example
tollbooth Generic middleware to rate-limit HTTP requests. iris-contrib/middleware/tollbooth/_examples/limit-handler
cloudwatch AWS cloudwatch metrics middleware. iris-contrib/middleware/cloudwatch/_example
new relic Official New Relic Go Agent. iris-contrib/middleware/newrelic/_example
prometheus Easily create metrics endpoint for the prometheus instrumentation tool iris-contrib/middleware/prometheus/_example

v7.x is deprecated because it sold as it is and it is not part of the public, stable gopkg.in iris versions. Developers/users of this library should upgrade their apps to v8.x, the refactor process will cost nothing for most of you, as the most common API remains as it was. The changelog history from that are being presented below.

Th, 15 June 2017 | v7.2.0

About our new home page

https://iris-go.com

Thanks to Santosh Anand the https://iris-go.com has been upgraded and it's really awesome!

Santosh is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.

The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!

Cache

Declare the iris.Cache alias to the new, improved and most-suited for common usage, cache.Handler function.

iris.Cache be used as middleware in the chain now, example here. However you can still use the cache as a wrapper by importing the github.com/kataras/iris/cache package.

File server

  • Fix that.

  • app.StaticHandler(requestPath string, systemPath string, showList bool, gzip bool) -> app.StaticHandler(systemPath,showList bool, gzip bool)

  • New feature for Single Page Applications, app.SPA(assetHandler context.Handler) implemented.

  • New app.StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) added in order to be able to pass that on app.SPA(app.StaticEmbeddedHandler("./public", Asset, AssetNames)).

  • Fix app.StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string).

Examples:

app.StaticWeb doesn't works for root request path "/" anymore, use the new app.SPA instead.

WWW subdomain entry

  • Example added to copy all application's routes, including parties, to the www.mydomain.com

Wrapping the Router

  • Example added to show you how you can use the app.WrapRouter
    to implement a similar to app.SPA functionality, don't panic, it's easier than it sounds.

Testing

  • httptest.New(app *iris.Application, t *testing.T) -> httptest.New(t *testing.T, app *iris.Application).

  • New httptest.NewLocalListener() net.Listener added.

  • New httptest.NewLocalTLSListener(tcpListener net.Listener) net.Listener added.

Useful for testing tls-enabled servers:

Proxies are trying to understand local addresses in order to allow InsecureSkipVerify.

  • host.ProxyHandler(target *url.URL) *httputil.ReverseProxy.

  • host.NewProxy(hostAddr string, target *url.URL) *Supervisor.

    Tests here.

Tu, 13 June 2017 | v7.1.1

Fix that.

Mo, 12 June 2017 | v7.1.0

Fix that.

Su, 11 June 2017 | v7.0.5

Iris now supports static paths and dynamic paths for the same path prefix with zero performance cost:

app.Get("/profile/{id:int}", handler) and app.Get("/profile/create", createHandler) are not in conflict anymore.

The rest of the special Iris' routing features, including static & wildcard subdomains are still work like a charm.

This was one of the most popular community's feature requests. Click here to see a trivial example.

Sa, 10 June 2017 | v7.0.4

  • Simplify and add a test for the basicauth middleware, no need to be
    stored inside the Context anymore, developers can get the validated user(username and password) via context.Request().BasicAuth(). basicauth.Config.ContextKey was removed, just remove that field from your configuration, it's useless now.

Sa, 10 June 2017 | v7.0.3

  • New context.Session().PeekFlash("key") added, unlike GetFlash this will return the flash value but keep the message valid for the next requests too.
  • Complete the httptest example.
  • Fix the (marked as deprecated) ListenLETSENCRYPT function.
  • Upgrade the iris-contrib/middleware including JWT, CORS and Secure handlers.
  • Add OAuth2 example -- showcases the third-party package goth integration with Iris.

Community

Th, 08 June 2017 | v7.0.2

  • Able to set immutable data on sessions and context's storage. Aligned to fix an issue on slices and maps as reported here.

We, 07 June 2017 | v7.0.1

  • Proof of concept of an internal release generator, navigate here to read more.
  • Remove tray icon "feature", click here to learn why.

Sa, 03 June 2017

After 2+ months of hard work and collaborations, Iris version 7 was published earlier today.

If you're new to Iris you don't have to read all these, just navigate to the updated examples and you should be fine:)

Note that this section will not
cover the internal changes, the difference is so big that anybody can see them with a glimpse, even the code structure itself.

Changes from v6

The whole framework was re-written from zero but I tried to keep the most common public API that iris developers use.

Vendoring /w update

The previous vendor action for v6 was done by-hand, now I'm using the go dep tool, I had to do
some small steps:

  • remove files like testdata to reduce the folder size
  • rollback some of the "golang/x/net/ipv4" and "ipv6" source files because they are downloaded to their latest versions
    by go dep, but they had lines with the typealias feature, which is not ready by current golang version (it will be on August)
  • fix "cannot use internal package" at golang/x/net/ipv4 and ipv6 packages
    • rename the interal folder to was-internal, everywhere and fix its references.
  • fix "main redeclared in this block"
    • remove all examples folders.
  • remove main.go files on jsondiff lib, used by gavv/httpexpect, produces errors on test -v ./... while jd and jp folders are not used at all.

The go dep tool does what is says, as expected, don't be afraid of it now.
I am totally recommending this tool for package authors, even if it's in its alpha state.
I remember when Iris was in its alpha state and it had 4k stars on its first weeks/or month and that helped me a lot to fix reported bugs by users and make the framework even better, so give love to go dep from today!

General

  • Several enhancements for the typescript transpiler, view engine, websocket server and sessions manager
  • All Listen methods replaced with a single Run method, see here
  • Configuration, easier to modify the defaults, see here
  • HandlerFunc removed, just Handler of func(context.Context) where context.Context derives from import "github.com/kataras/iris/context" (NEW: this import path is optional, use iris.Context if you've installed Go 1.9)
    • Simplify API, i.e: instead of Handle,HandleFunc,Use,UseFunc,Done,DoneFunc,UseGlobal,UseGlobalFunc use Handle,Use,Done,UseGlobal.
  • Response time decreased even more (9-35%, depends on the application)
  • The Adaptors idea replaced with a more structural design pattern, but you have to apply these changes:
    • app.Adapt(view.HTML/Pug/Amber/Django/Handlebars...) -> app.AttachView(view.HTML/Pug/Amber/Django/Handlebars...)
    • app.Adapt(sessions.New(...)) -> app.AttachSessionManager(sessions.New(...))
    • app.Adapt(iris.LoggerPolicy(...)) -> app.AttachLogger(io.Writer)
    • app.Adapt(iris.RenderPolicy(...)) -> removed and replaced with the ability to replace the whole context with a custom one or override some methods of it, see below.

Routing

  • Remove of multiple routers, now we have the fresh Iris router which is based on top of the julien's httprouter.

    Update 11 June 2017: As of 7.0.5 this is changed, read here.

  • Subdomains routing algorithm has been improved.
  • Iris router is using a custom interpreter with parser and path evaluator to achieve the best expressiveness, with zero performance loss, you ever seen so far, i.e:
    • app.Get("/", "/users/{userid:int min(1)}", handler),
      • {username:string} or just {username}
      • {asset:path},
      • {firstname:alphabetical},
      • {requestfile:file} ,
      • {mylowercaseParam regexp([a-z]+)}.
      • The previous syntax of :param and *param still working as expected. Previous rules for paths confliction remain as they were.
        • Also, path parameter names should be only alphabetical now, numbers and symbols are not allowed (for your own good, I have seen a lot the last year...).

Click here for details.

It was my first attempt/experience on the interpreters field, so be good with it :)

Context

  • iris.Context pointer replaced with context.Context interface as we already mention
    • in order to be able to use a custom context and/or catch lifetime like BeginRequest and EndRequest from context itself, see below
  • context.JSON, context.JSONP, context.XML, context.Markdown, context.HTML work faster
  • context.Render("filename.ext", bindingViewData{}, options) -> context.View("filename.ext")
    • View renders only templates, it will not try to search if you have a restful renderer adapted, because, now, you can do it via method overriding using a custom Context.
    • Able to set context.ViewData and context.ViewLayout via middleware when executing a template.
  • context.SetStatusCode(statusCode) -> context.StatusCode(statusCode)
    • which is equivalent with the old EmitError too:
      • if status code >=400 given can automatically fire a custom http error handler if response wasn't written already.
    • context.StatusCode() -> context.GetStatusCode()
    • app.OnError -> app.OnErrorCode
    • Errors per party are removed by-default, you can just use one global error handler with logic like "if path starts with 'prefix' fire this error handler, else...".
  • Easy way to change Iris' default Context with a custom one, see here
  • context.ResponseWriter().SetBeforeFlush(...) works for Flush and HTTP/2 Push, respectfully
  • Several improvements under the Request transactions
  • Remember that you had to set a status code on each of the render-relative methods? Now it's not required, it just renders
    with the status code that user gave with context.StatusCode or with 200 OK, i.e:
    -context.JSON(iris.StatusOK, myJSON{}) -> context.JSON(myJSON{}).
    • Each one of the context's render methods has optional per-call settings,
    • the new API is even more easier to read, understand and use.

Server

  • Able to set custom underline *http.Server(s) with new Host (aka Server Supervisor) feature
    • Done and Err channels to catch shutdown or any errors on custom hosts,
    • Schedule custom tasks(with cancelation) when server is running, see here
  • Interrupt handler task for gracefully shutdown (when CTRL/CMD+C) are enabled by-default, you can disable its via configuration: app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler)

Future plans

  • Future Go1.9's ServeTLS is ready when 1.9 released
  • Future Go1.9's typealias feature is ready when 1.9 released, i.e context.Context -> iris.Context just one import path instead of todays' two.

v8.5.4

@kataras kataras released this Oct 26, 2017 · 231 commits to master since this release

FAQ

Looking for free and real-time support?

https://github.com/kataras/iris/issues
https://chat.iris-go.com

Looking for previous versions?

https://github.com/kataras/iris/releases

Should I upgrade my Iris?

Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready.

Iris uses the vendor directory feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes.

Th, 26 October 2017 | v8.5.4

This version is part of the releases.

Version Updater

Not any new features or fixes (all reported bugs are fixed) in this version, just a tiny improvement.

More friendly version checker!

Remember: If you don't want to keep the version checker and you're pretty sure that you will be able to keep your server up-to-date manually, then you can disable the auto updater via; app.Run(..., iris.WithoutVersionChecker).

We need your help with translations into your native language

Iris needs your help, please think about contributing to the translation of the README and https://iris-go.com, you will be rewarded.

Instructions can be found at: #796

Su, 22 October 2017 | v8.5.3

🎗️ People that you should follow

Help this project to continue deliver awesome and unique features with the higher code quality as possible by donating any amount via PayPal or BTC!

Name Amount Membership
Juan Sebastián Suárez Valencia 20 EUR Bronze
Bob Lee 20 EUR Bronze
Celso Luiz 50 EUR Silver
Ankur Srivastava 20 EUR Bronze
Damon Zhao 20 EUR Bronze
Exponity - Tech Company 30 EUR Bronze
Thomas Fritz 25 EUR Bronze
Thanos V. 20 EUR Bronze
George Opritescu 20 EUR Bronze
Lex Tang 20 EUR Bronze
Bill Q. 600 EUR Gold
Conrad Steenberg 25 EUR Bronze

Th, 12 October 2017 | v8.5.2

This version is part of the releases.

MVC

Add bool as a supported return value, if false then skips everything else and fires 404 not found.

New example which covers the Service and Repository layers side-by-side with the MVC Architectural pattern, clean and simple: _examples/mvc/overview.

Websocket

Fix(?) #782 by @jerson with PR: #783.

Minor

Add some minor comments for the view/django's origin type getters-- as pushed at PR: #765.

sessions/sessiondb/badger vendored with: e7517ec.

Tu, 10 October 2017 | v8.5.1

MVC

  • fix any manual or before middleware's ctx.ViewData(key, value) gets overridden by setting mvc.Controller.Data or return mvc.View {Data: ...}. See the test case.

Mo, 09 October 2017 | v8.5.0

MVC

Great news for our MVC Fans or if you're not you may want to use that powerful feature today, because of the smart coding and decisions the performance is quite the same to the pure handlers, see _benchmarks.

A Controller's field that is an interface can now be binded to any type that implements that interface.

Ability to send HTTP responses based on the Controller's method function's output values, see below;

Iris now gives you the ability to render a response based on the output values returned from the controller's method functions!

You can return any value of any type from a method function
and it will be sent to the client as expected.

  • if string then it's the body.
  • if string is the second output argument then it's the content type.
  • if int then it's the status code.
  • if error and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead.
  • if (int, error) and error is not nil then the response result will be the error's text with the status code as int.
  • if custom struct or interface{} or slice or map then it will be rendered as json, unless a string content type is following.
  • if mvc.Result then it executes its Dispatch function, so good design patters can be used to split the model's logic where needed.

The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before;

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/middleware/basicauth"
    "github.com/kataras/iris/mvc"
)

// Movie is our sample data structure.
type Movie struct {
    Name   string `json:"name"`
    Year   int    `json:"year"`
    Genre  string `json:"genre"`
    Poster string `json:"poster"`
}

// movies contains our imaginary data source.
var movies = []Movie{
    {
        Name:   "Casablanca",
        Year:   1942,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg",
    },
    {
        Name:   "Gone with the Wind",
        Year:   1939,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg",
    },
    {
        Name:   "Citizen Kane",
        Year:   1941,
        Genre:  "Mystery",
        Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg",
    },
    {
        Name:   "The Wizard of Oz",
        Year:   1939,
        Genre:  "Fantasy",
        Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg",
    },
}


var basicAuth = basicauth.New(basicauth.Config{
    Users: map[string]string{
        "admin": "password",
    },
})


func main() {
    app := iris.New()

    app.Use(basicAuth)

    app.Controller("/movies", new(MoviesController))

    app.Run(iris.Addr(":8080"))
}

// MoviesController is our /movies controller.
type MoviesController struct {
    // mvc.C is just a lightweight lightweight alternative
    // to the "mvc.Controller" controller type,
    // use it when you don't need mvc.Controller's fields
    // (you don't need those fields when you return values from the method functions).
    mvc.C
}

// Get returns list of the movies
// Demo:
// curl -i http://localhost:8080/movies
func (c *MoviesController) Get() []Movie {
    return movies
}

// GetBy returns a movie
// Demo:
// curl -i http://localhost:8080/movies/1
func (c *MoviesController) GetBy(id int) Movie {
    return movies[id]
}

// PutBy updates a movie
// Demo:
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
func (c *MoviesController) PutBy(id int) Movie {
    // get the movie
    m := movies[id]

    // get the request data for poster and genre
    file, info, err := c.Ctx.FormFile("poster")
    if err != nil {
        c.Ctx.StatusCode(iris.StatusInternalServerError)
        return Movie{}
    }
    file.Close()            // we don't need the file
    poster := info.Filename // imagine that as the url of the uploaded file...
    genre := c.Ctx.FormValue("genre")

    // update the poster
    m.Poster = poster
    m.Genre = genre
    movies[id] = m

    return m
}

// DeleteBy deletes a movie
// Demo:
// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1
func (c *MoviesController) DeleteBy(id int) iris.Map {
    // delete the entry from the movies slice
    deleted := movies[id].Name
    movies = append(movies[:id], movies[id+1:]...)
    // and return the deleted movie's name
    return iris.Map{"deleted": deleted}
}

Another good example with a typical folder structure, that many developers are used to work, is located at the new README.md under the Quick MVC Tutorial #3 section.

Fr, 06 October 2017 | v8.4.5

  • Badger team added support for transactions yesterday, therefore the badger session database is updated via 0b48927.
  • MVC: Support more than one path parameters with a single By, when the By keyword is the last word and the func's input arguments are more than one i.e GetBy(name string, age int), note that you can still use the older way of doing this; GetByBy(string, int). It's an enhancement of the #751 feature request.
  • MVC: Give controllers the ability to auto-initialize themselves by OnActivate func derives from the new ActivateListener interface, this can be used to perform any custom actions when the app registers the supported Controllers. See mvc/session_controller.go for a good use case.
  • errors.Reporter.AddErr returns true if the error is added to the stack, otherwise false.
  • @ZaniaDeveloper fixed #778 with PR: #779.
  • Add StatusSeeOther at mvc login example for Redirection, reported by @motecshine at #777.
  • Fix DisableVersionChecker configuration field is not being passed correctly when it was true via iris.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...}) call.

Su, 01 October 2017 | v8.4.4

  • Fix #762 reported by @xkylsoft
  • Fix #771 reported by @cdren
  • Improvements to the memstore's GetInt, GetInt64, GetFloat64, GetBool and remove the golang/net/context's interface completion from Context, read the changes for more
  • Add two examples for folder structuring as requested at #748
  • Add node.js express benchmarks similar to iris and netcore

We, 27 September 2017 | v8.4.3

Fr, 15 September 2017 | v8.4.2

MVC

Support more than one dynamic method function receivers.

package main

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Controller("/user", new(UserController))
    app.Run(iris.Addr("localhost:8080"))
}

type UserController struct { iris.Controller }

// Maps to GET /user
// Request example: http://localhost:8080/user
// as usual.
func (c *UserController) Get() {
    c.Text = "hello from /user"
}

// Maps to GET /user/{paramfirst:long}
// Request example: http://localhost:8080/user/42
// as usual.
func (c *UserController) GetBy(userID int64) {
    c.Ctx.Writef("hello user with id: %d", userID)
}

// NEW:
// Maps to GET /user/{paramfirst:long}/business/{paramsecond:long}
// Request example: http://localhost:8080/user/42/business/93
func (c *UserController) GetByBusinessBy(userID int64, businessID int64) {
    c.Ctx.Writef("fetch a business id: %d that user with id: %d owns, may make your db query faster",
    businessID, userID)
}

Th, 07 September 2017 | v8.4.1

Routing

Add a macro type for booleans: app.Get("/mypath/{paramName:boolean}", myHandler).

+------------------------+
| {param:boolean}        |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"

Add context.Params().GetBool(paramName string) (bool, error) respectfully.

app := iris.New()
app.Get("/mypath/{has:boolean}", func(ctx iris.Context) { // <--
    // boolean first return value
    // error as second return value
    //
    // error will be always nil here because
    // we use the {has:boolean} so router
    // makes sure that the parameter is a boolean
    // otherwise it will return a 404 not found http error code
    // skipping the call of this handler.
    has, _ := ctx.Params().GetBool("has") // <--
    if has {
        ctx.HTML("<strong>it's true</strong>")
    }else {
        ctx.HTML("<strong>it's false</string>")
    }
})
// [...]

MVC

Support for boolean method receivers, i.e GetBy(bool), PostBy(bool)....

app := iris.New()

app.Controller("/equality", new(Controller))
type Controller struct {
    iris.Controller
}

// handles the "/equality" path.
func (c *Controller) Get() {

}

// registers and handles the path: "/equality/{param:boolean}".
func (c *Controller) GetBy(is bool) { // <--
    // [...]
}

Supported types for method functions receivers are: int, int64, bool and string.

Su, 27 August 2017 | v8.4.0

Miscellaneous

Router

Add a new macro type for path parameters, long, it's the go type int64.

app.Get("/user/{id:long}", func(ctx context.Context) {
	userID, _ := ctx.Params().GetInt64("id")
})

MVC

The ability to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that after a go get -u github.com/kataras/iris you will be able to use things like these:

If app.Controller("/user", new(user.Controller))

  • func(*Controller) Get() - GET:/user , as usual.
  • func(*Controller) Post() - POST:/user, as usual.
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

If app.Controller("/profile", new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

If app.Controller("/assets", new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

Example can be found at: _examples/mvc/login/user/controller.go.

Pretty awesome, right?

We, 23 August 2017 | v8.3.4

Give read access to the current request context's route, a feature that many of you asked a lot.

func(ctx context.Context) {
	_ = ctx.GetCurrentRoute().Name()
	//					.Method() returns string, same as ctx.Method().
	//					.Subdomain() returns string, the registered subdomain.
	//					.Path() returns string, the registered path.
	//					.IsOnline() returns boolean.
}
type MyController struct {
	mvc.Controller
}

func (c *MyController) Get(){
	_ = c.Route().Name() // same as `c.Ctx.GetCurrentRoute().Name()`.
	// [...]
}

Updated: 24 August 2017

This evening, on the next version 8.3.5:

Able to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that in the future you will be able to use something like these:

If app.Controller("/user", new(user.Controller))

  • func(c *Controller) Get() - GET:/user , as usual.
  • func(c *Controller) Post() - POST:/user, as usual.
  • func(c *Controller) GetLogin() - GET:/user/login
  • func(c *Controller) PostLogin() - POST:/user/login
  • func(c *Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(c *Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(c *Controller) GetBy() - GET:/user/{param}
  • func(c *Controller) GetByName(name string) - GET:/user/{name}
  • func(c *Controller) PostByName(name string) - POST:/user/{name}
  • func(c *Controller) GetByID(id int64 || int) - GET:/user/{id:int}
  • func(c *Controller) PostByID(id int64 || int) - POST:/user/{id:int}

Watch and stay tuned my friends.

We, 23 August 2017 | v8.3.3

Better debug messages when using MVC.

Add support for recursively binding and custom controllers embedded to other custom controller, that's the new feature. That simply means that Iris users are able to use "shared" controllers everywhere; when binding, using models, get/set persistence data, adding middleware, intercept request flow.

This will help web authors to split the logic at different controllers. Those controllers can be also used as "standalone" to serve a page somewhere else in the application as well.

My personal advice to you is to always organize and split your code nicely and wisely in order to avoid using such as an advanced MVC feature, at least any time soon.

I'm aware that this is not always an easy task to do, therefore is here if you ever need it :)

A ridiculous simple example of this feature can be found at the mvc/controller_test.go file.

Tu, 22 August 2017 | v8.3.2

MVC

When one or more values of handler type (func(ctx context.Context)) are passed
right to the controller initialization then they will be recognised and act as middleware(s)
that ran even before the controller activation, there is no reason to load
the whole controller if the main handler or its BeginRequest are not "allowed" to be executed.

Example Code

func checkLogin(ctx context.Context) {
	if !myCustomAuthMethodPassed {
		// [set a status or redirect, you know what to do]
		ctx.StatusCode(iris.StatusForbidden)
		return
	}

	// [continue to the next handler, at this example is our controller itself]
	ctx.Next()
}

// [...]
app.Controller(new(ProfileController), checkLogin)
// [...]

Usage of these kind of MVC features could be found at the mvc/controller_test.go file.

Other minor enhancements

  • fix issue #726*
  • fix redis sessiondb expiration*
  • update recursively when new version is available*
  • some minor session enhancements*

Sa, 19 August 2017 | v8.3.1

First of all I want to thank you for the 100% green feedback you gratefully sent me you about
my latest article Go vs .NET Core in terms of HTTP performance, published at medium's hackernoon.com and dev.to. I really appreciate it💓

No API Changes.

However two more methods added to the Controller.

  • RelPath() string, returns the relative path based on the controller's name and the request path.
  • RelTmpl() string, returns the relative template directory based on the controller's name.

These are useful when dealing with big controllers, they help you to keep align with any
future changes inside your application.

Want to learn more about these functions? Go to the mvc/controller_test.go file and scroll to the bottom!

Fr, 18 August 2017 | v8.3.0

Good news for devs that are used to write their web apps using the MVC architecture pattern.

Implement a whole new mvc package with additional support for models and easy binding.

@kataras started to develop that feature by version 8.2.5, back then it didn't seem
to be a large feature and maybe a game-changer, so it lived inside the kataras/iris/core/router/controller.go file.
However with this version, so many things are implemented for the MVC and we needed a new whole package,
this new package is the kataras/iris/mvc, but if you used go 1.9 to build then you don't have to do any refactor, you could use the iris.Controller type alias.

People who used the mvc from its baby steps(v8.2.5) the only syntactic change you'll have to do is to rename the router.Controller to mvc.Controller:

Before:

import "github.com/kataras/iris/core/router"
type MyController struct {
    router.Controller
}

Now:

import "github.com/kataras/iris/mvc"
type MyController struct {
    mvc.Controller
    // if you build with go1.9 you can omit the import of mvc package
    // and just use `iris.Controller` instead.
}

MVC (Model View Controller)

From version 8.3 and after Iris has first-class support for the MVC pattern, you'll not find
these stuff anywhere else in the Go world.

Example Code

package main

import (
	"sync"

	"github.com/kataras/iris"
	"github.com/kataras/iris/mvc"
)

func main() {
	app := iris.New()
	app.RegisterView(iris.HTML("./views", ".html"))

	// when we have a path separated by spaces
	// then the Controller is registered to all of them one by one.
	//
	// myDB is binded to the controller's `*DB` field: use only structs and pointers.
	app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
		new(ProfileController), myDB) // IMPORTANT

	app.Run(iris.Addr(":8080"))
}

// UserModel our example model which will render on the template.
type UserModel struct {
	ID       int64
	Username string
}

// DB is our example database.
type DB struct {
	usersTable map[int64]UserModel
	mu         sync.RWMutex
}

// GetUserByID imaginary database lookup based on user id.
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
	db.mu.RLock()
	u, found = db.usersTable[id]
	db.mu.RUnlock()
	return
}

var myDB = &DB{
	usersTable: map[int64]UserModel{
		1:  {1, "kataras"},
		2:  {2, "makis"},
		42: {42, "jdoe"},
	},
}

// ProfileController our example user controller which controls
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
type ProfileController struct {
	mvc.Controller // IMPORTANT

	User UserModel `iris:"model"`
	// we will bind it but you can also tag it with`iris:"persistence"`
	// and init the controller with manual &PorifleController{DB: myDB}.
	DB *DB
}

// Get method handles all "GET" HTTP Method requests of the controller's paths.
func (pc *ProfileController) Get() { // IMPORTANT
	path := pc.Path

	// requested: /profile path
	if path == "/profile" {
		pc.Tmpl = "profile/index.html"
		return
	}
	// requested: /profile/browse
	// this exists only to proof the concept of changing the path:
	// it will result to a redirection.
	if path == "/profile/browse" {
		pc.Path = "/profile"
		return
	}

	// requested: /profile/me path
	if path == "/profile/me" {
		pc.Tmpl = "profile/me.html"
		return
	}

	// requested: /profile/$ID
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound
		pc.Tmpl = "profile/notfound.html"
		pc.Data["ID"] = id
		return
	}

	pc.Tmpl = "profile/profile.html"
	pc.User = user
}


/*
func (pc *ProfileController) Post() {}
func (pc *ProfileController) Put() {}
func (pc *ProfileController) Delete() {}
func (pc *ProfileController) Connect() {}
func (pc *ProfileController) Head() {}
func (pc *ProfileController) Patch() {}
func (pc *ProfileController) Options() {}
func (pc *ProfileController) Trace() {}
*/

/*
func (pc *ProfileController) All() {}
//        OR
func (pc *ProfileController) Any() {}
*/

Iris web framework supports Request data, Models, Persistence Data and Binding
with the fastest possible execution.

Characteristics

All HTTP Methods are supported, for example if want to serve GET
then the controller should have a function named Get(),
you can define more than one method function to serve in the same Controller struct.

Persistence data inside your Controller struct (share data between requests)
via iris:"persistence" tag right to the field or Bind using app.Controller("/" , new(myController), theBindValue).

Models inside your Controller struct (set-ed at the Method function and rendered by the View)
via iris:"model" tag right to the field, i.e User UserModel `iris:"model" name:"user"` view will recognise it as {{.user}}.
If name tag is missing then it takes the field's name, in this case the "User".

Access to the request path and its parameters via the Path and Params fields.

Access to the template file that should be rendered via the Tmpl field.

Access to the template data that should be rendered inside
the template file via Data field.

Access to the template layout via the Layout field.

Access to the low-level context.Context via the Ctx field.

Get the relative request path by using the controller's name via RelPath().

Get the relative template path directory by using the controller's name via RelTmpl().

Flow as you used to, Controllers can be registered to any Party,
including Subdomains, the Party's begin and done handlers work as expected.

Optional BeginRequest(ctx) function to perform any initialization before the method execution,
useful to call middlewares or when many methods use the same collection of data.

Optional EndRequest(ctx) function to perform any finalization after any method executed.

Inheritance, recursively, see for example our mvc.SessionController, it has the mvc.Controller as an embedded field
and it adds its logic to its BeginRequest, here.

Read access to the current route via the Route field.

Using Iris MVC for code reuse

By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.

If you're new to back-end web development read about the MVC architectural pattern first, a good start is that wikipedia article.

Follow the examples below,

https://github.com/kataras/iris/tree/master/_examples/#mvc

Bugs

Fix #723 reported by @speedwheel.

Mo, 14 August 2017 | v8.2.6

Able to call done/end handlers inside a Controller, via optional EndRequest(ctx context.Context) function inside the controller struct.

// it's called after t.Get()/Post()/Put()/Delete()/Connect()/Head()/Patch()/Options()/Trace().
func (t *testControllerEndRequestFunc) EndRequest(ctx context.Context) {
    // 2.
    // [your code goes here...]
}

// will handle "GET" request HTTP method only.
func (t *testControllerEndRequestFunc) Get() {
    // 1.
    // [your code goes here...]
}

Look at the v8.2.5 changelog to learn more about the new Iris Controllers feature.

Su, 13 August 2017 | v8.2.5

Good news for devs that are used to write their web apps using the MVC-style app architecture.

Yesterday I wrote a tutorial on how you can transform your raw Handlers to Controllers using the existing tools only (Iris is the most modular web framework out there, we all have no doubt about this).

Today, I did implement the Controller idea as built'n feature inside Iris.
Our Controller supports many things among them are:

  • all HTTP Methods are supported, for example if want to serve GET then the controller should have a function named Get(), you can define more than one method function to serve in the same Controller struct
  • persistence data inside your Controller struct (share data between requests) via iris:"persistence" tag right to the field
  • optional BeginRequest(ctx) function to perform any initialization before the methods, useful to call middlewares or when many methods use the same collection of data
  • optional EndRequest(ctx) function to perform any finalization after the methods executed
  • access to the request path parameters via the Params field
  • access to the template file that should be rendered via the Tmpl field
  • access to the template data that should be rendered inside the template file via Data field
  • access to the template layout via the Layout field
  • access to the low-level context.Context via the Ctx field
  • flow as you used to, Controllers can be registered to any Party, including Subdomains, the Party's begin and done handlers work as expected.

It's very easy to get started, the only function you need to call instead of app.Get/Post/Put/Delete/Connect/Head/Patch/Options/Trace is the app.Controller.

Example Code:

// file: main.go

package main

import (
    "github.com/kataras/iris"

    "controllers"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    app.Controller("/", new(controllers.Index))

    // http://localhost:8080/
    app.Run(iris.Addr(":8080"))
}
// file: controllers/index.go

package controllers

import (
    "github.com/kataras/iris/core/router"
)

// Index is our index example controller.
type Index struct {
    mvc.Controller
    // if you're using go1.9: 
    // you can omit the /core/router import statement
    // and just use the `iris.Controller` instead.
}

// will handle GET method on http://localhost:8080/
func (c *Index) Get() {
    c.Tmpl = "index.html"
    c.Data["title"] = "Index page"
    c.Data["message"] = "Hello world!"
}

// will handle POST method on http://localhost:8080/
func (c *Index) Post() {}

Tip: declare a func(c *Index) All() {} or Any() to register all HTTP Methods.

A full example can be found at the _examples/mvc folder.

Sa, 12 August 2017 | v8.2.4

No API Changes.

Fix #717, users are welcomed to follow the thread for any questions or reports about Gzip and Static Files Handlers only.

Th, 10 August 2017 | v8.2.3

No API Changes.

Fix #714

Continue to v8.2.2 for more...

Th, 10 August 2017 | v8.2.2

No API Changes.

  • Implement Google reCAPTCHA middleware, example here
  • Fix kataras/golog prints with colors on windows server 2012 while it shouldn't because its command line tool does not support 256bit colors
  • Improve the updater by a custom self-updated back-end version checker, can be disabled by:
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)

Or

app.Configure(iris.WithoutVersionChecker)

Or

app.Configure(iris.WithConfiguration(iris.Configuration{DisableVersionChecker:true}))

Tu, 08 August 2017 | v8.2.1

No API Changes. Great news for the unique iris sessions library, once again.

NEW: LevelDB-based session database implemented, example here.

Redis-based sessiondb has no longer the MaxAgeSeconds config field,
this is passed automatically by the session manager, now.

All sessions databases have an Async(bool) function, if turned on
then all synchronization between the memory store and the back-end database will happen
inside different go routines. By-default async is false but it's recommended to turn it on, it will make sessions to be stored faster, at most.

All reported issues have been fixed, the API is simplified by v8.2.0 so everyone can
create and use any back-end storage for application's sessions persistence.

Mo, 07 August 2017 | v8.2.0

No Common-API Changes.

Good news for iris sessions back-end databases users.

Info for session database authors Session Database API Changed to:
type Database interface {
	Load(sid string) RemoteStore
	Sync(p SyncPayload)
}

// SyncPayload reports the state of the session inside a database sync action.
type SyncPayload struct {
	SessionID string

	Action Action
	// on insert it contains the new key and the value
	// on update it contains the existing key and the new value
	// on delete it contains the key (the value is nil)
	// on clear it contains nothing (empty key, value is nil)
	// on destroy it contains nothing (empty key, value is nil)
	Value memstore.Entry
	// Store contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Store RemoteStore
}


// RemoteStore is a helper which is a wrapper
// for the store, it can be used as the session "table" which will be
// saved to the session database.
type RemoteStore struct {
	// Values contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Values memstore.Store
	// on insert it contains the expiration datetime
	// on update it contains the new expiration datetime(if updated or the old one)
	// on delete it will be zero
	// on clear it will be zero
	// on destroy it will be zero
	Lifetime LifeTime
}

Read more at sessions/database.go, view how three built'n session databases are being implemented here.

All sessions databases are updated and they performant even faster than before.

  • NEW raw file-based session database implemented, example here
  • NEW boltdb-based session database implemented, example here (recommended as it's safer and faster)
  • redis sessiondb updated to the latest api

Under the cover, session database works entirely differently than before but nothing changed from the user's perspective, so upgrade with go get -u github.com/kataras/iris and sleep well.

Tu, 01 August 2017 | v8.1.3

  • Add Option function to the html view engine: #694
  • Fix sessions backend databases restore expiration: #692 by @corebreaker
  • Add PartyFunc, same as Party but receives a function with the sub router as its argument instead [GO1.9 Users-ONLY]

Mo, 31 July 2017 | v8.1.2

Add a ConfigureHost function as an alternative way to customize the hosts via host.Configurator.
The first way was to pass host.Configurator as optional arguments on iris.Runners built'n functions (iris#Server, iris#Listener, iris#Addr, iris#TLS, iris#AutoTLS), example of this can be found there.

Example Code:

package main

import (
	stdContext "context"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/host"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx context.Context) {
		ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
	})

    app.ConfigureHost(configureHost) // or pass "configureHost" as `app.Addr` argument, same result.

	app.Logger().Info("Wait 10 seconds and check your terminal again")
	// simulate a shutdown action here...
	go func() {
		<-time.After(10 * time.Second)
		timeout := 5 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		// close all hosts, this will notify the callback we had register
		// inside the `configureHost` func.
		app.Shutdown(ctx)
	}()

	// http://localhost:8080
	// wait 10 seconds and check your terminal.
	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func configureHost(su *host.Supervisor) {
	// here we have full access to the host that will be created
	// inside the `app.Run` or `app.NewHost` function .
	//
	// we're registering a shutdown "event" callback here:
	su.RegisterOnShutdown(func() {
		println("server is closed")
	})
	// su.RegisterOnError
	// su.RegisterOnServe
}

Su, 30 July 2017

Greetings my friends, nothing special today, no version number yet.

We just improve the, external, Iris Logging library and the Columns config field from middleware/logger defaults to false now. Upgrade with go get -u github.com/kataras/iris and have fun!

Sa, 29 July 2017 | v8.1.1

No breaking changes, just an addition to make your life easier.

This feature has been implemented after @corebreaker 's request, posted at: #688. He was also tried to fix that by a PR, we thanks him but the problem with that PR was the duplication and the separation of concepts, however we thanks him for pushing for a solution. The current feature's implementation gives a permant solution to host supervisor access issues.

Optional host configurators added to all common serve and listen functions.

Below you'll find how to gain access to the host, the second way is the new feature.

Hosts

Access to all hosts that serve your application can be provided by
the Application#Hosts field, after the Run method.

But the most common scenario is that you may need access to the host before the Run method,
there are two ways of gain access to the host supervisor, read below.

First way is to use the app.NewHost to create a new host
and use one of its Serve or Listen functions
to start the application via the iris#Raw Runner.
Note that this way needs an extra import of the net/http package.

Example Code:

h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){
    println("server was closed!")
})

app.Run(iris.Raw(h.ListenAndServe))

Second, and probably easier way is to use the host.Configurator.

Note that this method requires an extra import statement of
"github.com/kataras/iris/core/host" when using go < 1.9,
if you're targeting on go1.9 then you can use the iris#Supervisor
and omit the extra host import.

All common Runners we saw earlier (iris#Addr, iris#Listener, iris#Server, iris#TLS, iris#AutoTLS)
accept a variadic argument of host.Configurator, there are just func(*host.Supervisor).
Therefore the Application gives you the rights to modify the auto-created host supervisor through these.

Example Code:

package main

import (
    stdContext "context"
    "time"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
    "github.com/kataras/iris/core/host"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
        ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
    })

    app.Logger().Info("Wait 10 seconds and check your terminal again")
    // simulate a shutdown action here...
    go func() {
        <-time.After(10 * time.Second)
        timeout := 5 * time.Second
        ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
        defer cancel()
        // close all hosts, this will notify the callback we had register
        // inside the `configureHost` func.
        app.Shutdown(ctx)
    }()

    // start the server as usual, the only difference is that
    // we're adding a second (optional) function
    // to configure the just-created host supervisor.
    //
    // http://localhost:8080
    // wait 10 seconds and check your terminal.
    app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed))

}

func configureHost(su *host.Supervisor) {
    // here we have full access to the host that will be created
    // inside the `Run` function.
    //
    // we register a shutdown "event" callback
    su.RegisterOnShutdown(func() {
        println("server is closed")
    })
    // su.RegisterOnError
    // su.RegisterOnServe
}

Read more about listening and gracefully shutdown by navigating to: https://github.com/kataras/iris/tree/master/_examples/#http-listening

We, 26 July 2017 | v8.1.0

The app.Logger() *logrus.Logger was replaced with a custom implementation [golog], it's compatible with the logrus package and other open-source golang loggers as well, because of that: #680 (comment).

The API didn't change much except these:

  • the new implementation does not recognise Fatal and Panic because, actually, iris never panics
  • the old app.Logger().Out = io.Writer should be written as app.Logger().SetOutput(io.Writer)

The new implementation, golog is featured, three times faster than logrus
and it completes every common usage.

Integration

I understand that many of you may use logrus outside of Iris too. To integrate an external logrus logger just
Install it-- all print operations will be handled by the provided logrus instance.

import (
    "github.com/kataras/iris"
    "github.com/sirupsen/logrus"
)

package main(){
    app := iris.New()
    app.Logger().Install(logrus.StandardLogger()) // the package-level logrus instance
    // [...]
}

For more information about our new logger please navigate to: https://github.com/kataras/golog - contributions are welcomed as well!

Sa, 23 July 2017 | v8.0.7

Fix It's true that with UseGlobal the "/path1.txt" route call the middleware but cause the prepend, the order is inversed

Sa, 22 July 2017 | v8.0.5 & v8.0.6

No API Changes.

Performance

Add an experimental Configuration#EnableOptimizations option.

type Configuration {
    // [...]

    // EnableOptimization when this field is true
    // then the application tries to optimize for the best performance where is possible.
    //
    // Defaults to false.
    EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"`

    // [...]
}

Usage:

app.Run(iris.Addr(":8080"), iris.WithOptimizations)

Django view engine

@corebreaker pushed a PR to solve the Problem for {%extends%} in Django Engine with embedded files.

Logger

Remove the vendor/github.com/sirupsen/logrus folder, as a temporary solution for the #680 (comment).

Future versions

The logrus will be replaced with a custom implementation, because of that: #680 (comment).

As far as we know, @kataras is working on this new implementation, see here,
which will be compatible with the logrus package and other open-source golang loggers as well.

Mo, 17 July 2017 | v8.0.4

No API changes.

HTTP Errors

Fix a rare behavior: error handlers are not executed correctly
when a before-handler by-passes the order of execution, relative to the previous feature.

Request Logger

Add Configuration#MessageContextKey. Example can be found at _examples/http_request/request-logger/main.go.

Su, 16 July 2017 | v8.0.3

No API changes.

Relative issues:

HTTP Errors

Able to register a chain of Handlers (and middleware with ctx.Next() support like routes) for a specific error code, read more at issues/674. Usage example can be found at _examples/http_request/request-logger/main.go.

New function to register a Handler or a chain of Handlers for all official http error codes, by calling the new app.OnAnyErrorCode(func(ctx context.Context){}), read more at issues/675. Usage example can be found at _examples/http_request/request-logger/main.go.

Request Logger

Add Configuration#LogFunc and Configuration#Columns fields, read more at issues/676. Example can be found at _examples/http_request/request-logger/request-logger-file/main.go.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Sa, 15 July 2017 | v8.0.2

Okay my friends, this is a good time to upgrade, I did implement a feature that you were asking many times at the past.

Iris' router can now handle root-level wildcard paths app.Get("/{paramName:path}).

In case you're wondering: no it does not conflict with other static or dynamic routes, meaning that you can code something like this:

// it isn't conflicts with the rest of the static routes or dynamic routes with a path prefix.
app.Get("/{pathParamName:path}", myHandler) 

Or even like this:

package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
)

func main() {
	app := iris.New()

	// this works as expected now,
	// will handle all GET requests
	// except:
	// /                     -> because of app.Get("/", ...)
	// /other/anything/here  -> because of app.Get("/other/{paramother:path}", ...)
	// /other2/anything/here -> because of app.Get("/other2/{paramothersecond:path}", ...)
	// /other2/static        -> because of app.Get("/other2/static", ...)
	//
	// It isn't conflicts with the rest of the routes, without routing performance cost!
	//
	// i.e /something/here/that/cannot/be/found/by/other/registered/routes/order/not/matters
	app.Get("/{p:path}", h)

	// this will handle only GET /
	app.Get("/", staticPath)

	// this will handle all GET requests starting with "/other/"
	//
	// i.e /other/more/than/one/path/parts
	app.Get("/other/{paramother:path}", other)

	// this will handle all GET requests starting with "/other2/"
	// except /other2/static (because of the next static route)
	//
	// i.e /other2/more/than/one/path/parts
	app.Get("/other2/{paramothersecond:path}", other2)

	// this will handle only GET /other2/static
	app.Get("/other2/static", staticPath)

	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func h(ctx context.Context) {
	param := ctx.Params().Get("p")
	ctx.WriteString(param)
}

func other(ctx context.Context) {
	param := ctx.Params().Get("paramother")
	ctx.Writef("from other: %s", param)
}

func other2(ctx context.Context) {
	param := ctx.Params().Get("paramothersecond")
	ctx.Writef("from other2: %s", param)
}

func staticPath(ctx context.Context) {
	ctx.Writef("from the static path: %s", ctx.Path())
}

If you find any bugs with this change please send me a chat message in order to investigate it, I'm totally free at weekends.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Th, 13 July 2017 | v8.0.1

Nothing tremendous at this minor version.

We've just added a configuration field in order to ignore errors received by the Run function, see below.

Configuration#IgnoreServerErrors

type Configuration struct {
    // [...]

    // IgnoreServerErrors will cause to ignore the matched "errors"
    // from the main application's `Run` function.
    // This is a slice of string, not a slice of error
    // users can register these errors using yaml or toml configuration file
    // like the rest of the configuration fields.
    //
    // See `WithoutServerError(...)` function too.
    //
    // Defaults to an empty slice.
    IgnoreServerErrors []string `yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`

    // [...]
}

Configuration#WithoutServerError

// WithoutServerError will cause to ignore the matched "errors"
// from the main application's `Run` function.
//
// Usage:
// err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
//
// See `Configuration#IgnoreServerErrors []string` too.
WithoutServerError(errors ...error) Configurator

By default no error is being ignored, of course.

Example code:
_examples/http-listening/listen-addr/omit-server-errors

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
    	ctx.HTML("<h1>Hello World!/</h1>")
    })

    err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    if err != nil {
        // do something
    }
    // same as:
    // err := app.Run(iris.Addr(":8080"))
    // if err != nil && (err != iris.ErrServerClosed || err.Error() != iris.ErrServerClosed.Error()) {
    //     [...]
    // }
}

At first we didn't want to implement something like that because it's ridiculous easy to do it manually but a second thought came to us,
that many applications are based on configuration, therefore it would be nice to have something to ignore errors
by simply string values that can be passed to the application's configuration via toml or yaml files too.

This feature has been implemented after a request of ignoring the iris/http#ErrServerClosed from the Run function:
#668

Mo, 10 July 2017 | v8.0.0

📈 One and a half years with Iris and You...

Despite the deflamations, the clickbait articles, the removed posts of mine at reddit/r/golang, the unexpected and inadequate ban from the gophers slack room by @dlsniper alone the previous week without any reason or inform, Iris is still here and will be.

  • 7070 github stars
  • 749 github forks
  • 1m total views at its documentation
  • ~800$ at donations (there're a lot for a golang open-source project, thanks to you)
  • ~550 reported bugs fixed
  • ~30 community feature requests have been implemented

🔥 Reborn

As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore.

After a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community.

The leadership of this, open-source, repository was transferred to hiveminded, the author of iris-based get-ion/ion, he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s).

UPDATE:

I am voluntarily quiting this responsibility because I've been re-positioned as the new Lead Product Manager of the company I'm working for many years, which I accepted with honor. That's a very time consuming position I'm responsible to accomplish and deliver, therefore, I transfer all my rights back to @kataras and I resign from any copyrights over this project. My contribution clearly didn't make the difference but I owe a big "thank you" to Gerasimos for the chance he gave me and I hope the bests for him and iris. Thank you all.

These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me!

📰 Changelog

app. = app := iris.New(); app.

ctx. = func(ctx context.Context) { ctx. }

Docker

Docker and kubernetes integration showcase, see the iris-contrib/cloud-native-go repository as an example.

Logger

  • Logger which was an io.Writer was replaced with the pluggable logrus.
    • which you still attach an io.Writer with app.Logger().Out = an io.Writer.
    • iris as always logs only critical errors, you can disable them with app.Logger().Level = iris.NoLog
    • the request logger outputs the incoming requests as INFO level.

Sessions

Remove ctx.Session() and app.AttachSessionManager, devs should import and use the sessions package as standalone, it's totally optional, devs can use any other session manager too. Examples here.

Websockets

The github.com/kataras/iris/websocket package does not handle the endpoint and client side automatically anymore. Example code:

func setupWebsocket(app *iris.Application) {
    // create our echo websocket server
    ws := websocket.New(websocket.Config{
    	ReadBufferSize:  1024,
    	WriteBufferSize: 1024,
    })
    ws.OnConnection(handleConnection)
    // serve the javascript built'n client-side library,
    // see weboskcets.html script tags, this path is used.
    app.Any("/iris-ws.js", func(ctx context.Context) {
    	ctx.Write(websocket.ClientSource)
    })

    // register the server on an endpoint.
    // see the inline javascript code in the websockets.html, this endpoint is used to connect to the server.
    app.Get("/echo", ws.Handler())
}

More examples here

View

Rename app.AttachView(...) to app.RegisterView(...).

Users can omit the import of github.com/kataras/iris/view and use the github.com/kataras/iris package to
refer to the view engines, i.e: app.RegisterView(iris.HTML("./templates", ".html")) is the same as import "github.com/kataras/iris/view" [...] app.RegisterView(view.HTML("./templates" ,".html")).

Examples here

Security

At previous versions, when you called ctx.Remoteaddr() Iris could parse and return the client's IP from the "X-Real-IP", "X-Forwarded-For" headers. This was a security leak as you can imagine, because the user can modify them. So we've disabled these headers by-default and add an option to add/remove request headers that are responsible to parse and return the client's real IP.

// WithRemoteAddrHeader enables or adds a new or existing request header name
// that can be used to validate the client's real IP.
//
// Existing values are:
// "X-Real-Ip":             false,
// "X-Forwarded-For":       false,
// "CF-Connecting-IP": false
//
// Look `context.RemoteAddr()` for more.
WithRemoteAddrHeader(headerName string) Configurator // enables a header.
WithoutRemoteAddrHeader(headerName string) Configurator // disables a header.

For example, if you want to enable the "CF-Connecting-IP" header (cloudflare)
you have to add the WithRemoteAddrHeader option to the app.Run function, at the end of your program.

app.Run(iris.Addr(":8080"), iris.WithRemoteAddrHeader("CF-Connecting-IP"))
// This header name will be checked when ctx.RemoteAddr() called and if exists
// it will return the client's IP, otherwise it will return the default *http.Request's `RemoteAddr` field.

Miscellaneous

Fix typescript tools.

_examples folder has been ordered by feature and usage:
- contains tests on some examples
- new examples added, one of them shows how the reuseport feature on UNIX and BSD systems can be used to listen for incoming connections, see here

Replace supervisor's tasks with events, like RegisterOnShutdown, RegisterOnError, RegisterOnServe and fix the (unharmful) race condition when output the banner to the console. Global notifier for interrupt signals which can be disabled via app.Run([...], iris.WithoutInterruptHandler), look graceful-shutdown example for more.

More handlers are ported to Iris (they can be used as they are without iris.FromStd), these handlers can be found at iris-contrib/middleware. Feel free to put your own there.

Middleware Description Example
jwt Middleware checks for a JWT on the Authorization header on incoming requests and decodes it. iris-contrib/middleware/jwt/_example
cors HTTP Access Control. iris-contrib/middleware/cors/_example
secure Middleware that implements a few quick security wins. iris-contrib/middleware/secure/_example
tollbooth Generic middleware to rate-limit HTTP requests. iris-contrib/middleware/tollbooth/_examples/limit-handler
cloudwatch AWS cloudwatch metrics middleware. iris-contrib/middleware/cloudwatch/_example
new relic Official New Relic Go Agent. iris-contrib/middleware/newrelic/_example
prometheus Easily create metrics endpoint for the prometheus instrumentation tool iris-contrib/middleware/prometheus/_example

v7.x is deprecated because it sold as it is and it is not part of the public, stable gopkg.in iris versions. Developers/users of this library should upgrade their apps to v8.x, the refactor process will cost nothing for most of you, as the most common API remains as it was. The changelog history from that are being presented below.

Th, 15 June 2017 | v7.2.0

About our new home page

https://iris-go.com

Thanks to Santosh Anand the https://iris-go.com has been upgraded and it's really awesome!

Santosh is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.

The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!

Cache

Declare the iris.Cache alias to the new, improved and most-suited for common usage, cache.Handler function.

iris.Cache be used as middleware in the chain now, example here. However you can still use the cache as a wrapper by importing the github.com/kataras/iris/cache package.

File server

  • Fix that.

  • app.StaticHandler(requestPath string, systemPath string, showList bool, gzip bool) -> app.StaticHandler(systemPath,showList bool, gzip bool)

  • New feature for Single Page Applications, app.SPA(assetHandler context.Handler) implemented.

  • New app.StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) added in order to be able to pass that on app.SPA(app.StaticEmbeddedHandler("./public", Asset, AssetNames)).

  • Fix app.StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string).

Examples:

app.StaticWeb doesn't works for root request path "/" anymore, use the new app.SPA instead.

WWW subdomain entry

  • Example added to copy all application's routes, including parties, to the www.mydomain.com

Wrapping the Router

  • Example added to show you how you can use the app.WrapRouter
    to implement a similar to app.SPA functionality, don't panic, it's easier than it sounds.

Testing

  • httptest.New(app *iris.Application, t *testing.T) -> httptest.New(t *testing.T, app *iris.Application).

  • New httptest.NewLocalListener() net.Listener added.

  • New httptest.NewLocalTLSListener(tcpListener net.Listener) net.Listener added.

Useful for testing tls-enabled servers:

Proxies are trying to understand local addresses in order to allow InsecureSkipVerify.

  • host.ProxyHandler(target *url.URL) *httputil.ReverseProxy.

  • host.NewProxy(hostAddr string, target *url.URL) *Supervisor.

    Tests here.

Tu, 13 June 2017 | v7.1.1

Fix that.

Mo, 12 June 2017 | v7.1.0

Fix that.

Su, 11 June 2017 | v7.0.5

Iris now supports static paths and dynamic paths for the same path prefix with zero performance cost:

app.Get("/profile/{id:int}", handler) and app.Get("/profile/create", createHandler) are not in conflict anymore.

The rest of the special Iris' routing features, including static & wildcard subdomains are still work like a charm.

This was one of the most popular community's feature requests. Click here to see a trivial example.

Sa, 10 June 2017 | v7.0.4

  • Simplify and add a test for the basicauth middleware, no need to be
    stored inside the Context anymore, developers can get the validated user(username and password) via context.Request().BasicAuth(). basicauth.Config.ContextKey was removed, just remove that field from your configuration, it's useless now.

Sa, 10 June 2017 | v7.0.3

  • New context.Session().PeekFlash("key") added, unlike GetFlash this will return the flash value but keep the message valid for the next requests too.
  • Complete the httptest example.
  • Fix the (marked as deprecated) ListenLETSENCRYPT function.
  • Upgrade the iris-contrib/middleware including JWT, CORS and Secure handlers.
  • Add OAuth2 example -- showcases the third-party package goth integration with Iris.

Community

Th, 08 June 2017 | v7.0.2

  • Able to set immutable data on sessions and context's storage. Aligned to fix an issue on slices and maps as reported here.

We, 07 June 2017 | v7.0.1

  • Proof of concept of an internal release generator, navigate here to read more.
  • Remove tray icon "feature", click here to learn why.

Sa, 03 June 2017

After 2+ months of hard work and collaborations, Iris version 7 was published earlier today.

If you're new to Iris you don't have to read all these, just navigate to the updated examples and you should be fine:)

Note that this section will not
cover the internal changes, the difference is so big that anybody can see them with a glimpse, even the code structure itself.

Changes from v6

The whole framework was re-written from zero but I tried to keep the most common public API that iris developers use.

Vendoring /w update

The previous vendor action for v6 was done by-hand, now I'm using the go dep tool, I had to do
some small steps:

  • remove files like testdata to reduce the folder size
  • rollback some of the "golang/x/net/ipv4" and "ipv6" source files because they are downloaded to their latest versions
    by go dep, but they had lines with the typealias feature, which is not ready by current golang version (it will be on August)
  • fix "cannot use internal package" at golang/x/net/ipv4 and ipv6 packages
    • rename the interal folder to was-internal, everywhere and fix its references.
  • fix "main redeclared in this block"
    • remove all examples folders.
  • remove main.go files on jsondiff lib, used by gavv/httpexpect, produces errors on test -v ./... while jd and jp folders are not used at all.

The go dep tool does what is says, as expected, don't be afraid of it now.
I am totally recommending this tool for package authors, even if it's in its alpha state.
I remember when Iris was in its alpha state and it had 4k stars on its first weeks/or month and that helped me a lot to fix reported bugs by users and make the framework even better, so give love to go dep from today!

General

  • Several enhancements for the typescript transpiler, view engine, websocket server and sessions manager
  • All Listen methods replaced with a single Run method, see here
  • Configuration, easier to modify the defaults, see here
  • HandlerFunc removed, just Handler of func(context.Context) where context.Context derives from import "github.com/kataras/iris/context" (NEW: this import path is optional, use iris.Context if you've installed Go 1.9)
    • Simplify API, i.e: instead of Handle,HandleFunc,Use,UseFunc,Done,DoneFunc,UseGlobal,UseGlobalFunc use Handle,Use,Done,UseGlobal.
  • Response time decreased even more (9-35%, depends on the application)
  • The Adaptors idea replaced with a more structural design pattern, but you have to apply these changes:
    • app.Adapt(view.HTML/Pug/Amber/Django/Handlebars...) -> app.AttachView(view.HTML/Pug/Amber/Django/Handlebars...)
    • app.Adapt(sessions.New(...)) -> app.AttachSessionManager(sessions.New(...))
    • app.Adapt(iris.LoggerPolicy(...)) -> app.AttachLogger(io.Writer)
    • app.Adapt(iris.RenderPolicy(...)) -> removed and replaced with the ability to replace the whole context with a custom one or override some methods of it, see below.

Routing

  • Remove of multiple routers, now we have the fresh Iris router which is based on top of the julien's httprouter.

    Update 11 June 2017: As of 7.0.5 this is changed, read here.

  • Subdomains routing algorithm has been improved.
  • Iris router is using a custom interpreter with parser and path evaluator to achieve the best expressiveness, with zero performance loss, you ever seen so far, i.e:
    • app.Get("/", "/users/{userid:int min(1)}", handler),
      • {username:string} or just {username}
      • {asset:path},
      • {firstname:alphabetical},
      • {requestfile:file} ,
      • {mylowercaseParam regexp([a-z]+)}.
      • The previous syntax of :param and *param still working as expected. Previous rules for paths confliction remain as they were.
        • Also, path parameter names should be only alphabetical now, numbers and symbols are not allowed (for your own good, I have seen a lot the last year...).

Click here for details.

It was my first attempt/experience on the interpreters field, so be good with it :)

Context

  • iris.Context pointer replaced with context.Context interface as we already mention
    • in order to be able to use a custom context and/or catch lifetime like BeginRequest and EndRequest from context itself, see below
  • context.JSON, context.JSONP, context.XML, context.Markdown, context.HTML work faster
  • context.Render("filename.ext", bindingViewData{}, options) -> context.View("filename.ext")
    • View renders only templates, it will not try to search if you have a restful renderer adapted, because, now, you can do it via method overriding using a custom Context.
    • Able to set context.ViewData and context.ViewLayout via middleware when executing a template.
  • context.SetStatusCode(statusCode) -> context.StatusCode(statusCode)
    • which is equivalent with the old EmitError too:
      • if status code >=400 given can automatically fire a custom http error handler if response wasn't written already.
    • context.StatusCode() -> context.GetStatusCode()
    • app.OnError -> app.OnErrorCode
    • Errors per party are removed by-default, you can just use one global error handler with logic like "if path starts with 'prefix' fire this error handler, else...".
  • Easy way to change Iris' default Context with a custom one, see here
  • context.ResponseWriter().SetBeforeFlush(...) works for Flush and HTTP/2 Push, respectfully
  • Several improvements under the Request transactions
  • Remember that you had to set a status code on each of the render-relative methods? Now it's not required, it just renders
    with the status code that user gave with context.StatusCode or with 200 OK, i.e:
    -context.JSON(iris.StatusOK, myJSON{}) -> context.JSON(myJSON{}).
    • Each one of the context's render methods has optional per-call settings,
    • the new API is even more easier to read, understand and use.

Server

  • Able to set custom underline *http.Server(s) with new Host (aka Server Supervisor) feature
    • Done and Err channels to catch shutdown or any errors on custom hosts,
    • Schedule custom tasks(with cancelation) when server is running, see here
  • Interrupt handler task for gracefully shutdown (when CTRL/CMD+C) are enabled by-default, you can disable its via configuration: app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler)

Future plans

  • Future Go1.9's ServeTLS is ready when 1.9 released
  • Future Go1.9's typealias feature is ready when 1.9 released, i.e context.Context -> iris.Context just one import path instead of todays' two.

v8.5.2

@kataras kataras released this Oct 12, 2017 · 265 commits to master since this release

Looking for free support?

http://support.iris-go.com
https://chat.iris-go.com

Iris uses the vendor directory feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes.

Th, 12 October 2017 | v8.5.2

This version is part of the releases.

MVC

Add bool as a supported return value, if false then skips everything else and fires 404 not found.

New example which covers the Service and Repository layers side-by-side with the MVC Architectural pattern, clean and simple: _examples/mvc/overview.

Websocket

Fix(?) #782 by @jerson with PR: #783.

Minor

Add some minor comments for the view/django's origin type getters-- as pushed at PR: #765.

sessions/sessiondb/badger vendored with: e7517ec.

Tu, 10 October 2017 | v8.5.1

MVC

  • fix any manual or before middleware's ctx.ViewData(key, value) gets overridden by setting mvc.Controller.Data or return mvc.View {Data: ...}. See the test case.

Mo, 09 October 2017 | v8.5.0

MVC

Great news for our MVC Fans or if you're not you may want to use that powerful feature today, because of the smart coding and decisions the performance is quite the same to the pure handlers, see _benchmarks.

A Controller's field that is an interface can now be binded to any type that implements that interface.

Ability to send HTTP responses based on the Controller's method function's output values, see below;

Iris now gives you the ability to render a response based on the output values returned from the controller's method functions!

You can return any value of any type from a method function
and it will be sent to the client as expected.

  • if string then it's the body.
  • if string is the second output argument then it's the content type.
  • if int then it's the status code.
  • if error and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead.
  • if (int, error) and error is not nil then the response result will be the error's text with the status code as int.
  • if custom struct or interface{} or slice or map then it will be rendered as json, unless a string content type is following.
  • if mvc.Result then it executes its Dispatch function, so good design patters can be used to split the model's logic where needed.

The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before;

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/middleware/basicauth"
    "github.com/kataras/iris/mvc"
)

// Movie is our sample data structure.
type Movie struct {
    Name   string `json:"name"`
    Year   int    `json:"year"`
    Genre  string `json:"genre"`
    Poster string `json:"poster"`
}

// movies contains our imaginary data source.
var movies = []Movie{
    {
        Name:   "Casablanca",
        Year:   1942,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg",
    },
    {
        Name:   "Gone with the Wind",
        Year:   1939,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg",
    },
    {
        Name:   "Citizen Kane",
        Year:   1941,
        Genre:  "Mystery",
        Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg",
    },
    {
        Name:   "The Wizard of Oz",
        Year:   1939,
        Genre:  "Fantasy",
        Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg",
    },
}


var basicAuth = basicauth.New(basicauth.Config{
    Users: map[string]string{
        "admin": "password",
    },
})


func main() {
    app := iris.New()

    app.Use(basicAuth)

    app.Controller("/movies", new(MoviesController))

    app.Run(iris.Addr(":8080"))
}

// MoviesController is our /movies controller.
type MoviesController struct {
    // mvc.C is just a lightweight lightweight alternative
    // to the "mvc.Controller" controller type,
    // use it when you don't need mvc.Controller's fields
    // (you don't need those fields when you return values from the method functions).
    mvc.C
}

// Get returns list of the movies
// Demo:
// curl -i http://localhost:8080/movies
func (c *MoviesController) Get() []Movie {
    return movies
}

// GetBy returns a movie
// Demo:
// curl -i http://localhost:8080/movies/1
func (c *MoviesController) GetBy(id int) Movie {
    return movies[id]
}

// PutBy updates a movie
// Demo:
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
func (c *MoviesController) PutBy(id int) Movie {
    // get the movie
    m := movies[id]

    // get the request data for poster and genre
    file, info, err := c.Ctx.FormFile("poster")
    if err != nil {
        c.Ctx.StatusCode(iris.StatusInternalServerError)
        return Movie{}
    }
    file.Close()            // we don't need the file
    poster := info.Filename // imagine that as the url of the uploaded file...
    genre := c.Ctx.FormValue("genre")

    // update the poster
    m.Poster = poster
    m.Genre = genre
    movies[id] = m

    return m
}

// DeleteBy deletes a movie
// Demo:
// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1
func (c *MoviesController) DeleteBy(id int) iris.Map {
    // delete the entry from the movies slice
    deleted := movies[id].Name
    movies = append(movies[:id], movies[id+1:]...)
    // and return the deleted movie's name
    return iris.Map{"deleted": deleted}
}

Another good example with a typical folder structure, that many developers are used to work, is located at the new README.md under the Quick MVC Tutorial #3 section.

Fr, 06 October 2017 | v8.4.5

  • Badger team added support for transactions yesterday, therefore the badger session database is updated via 0b48927.
  • MVC: Support more than one path parameters with a single By, when the By keyword is the last word and the func's input arguments are more than one i.e GetBy(name string, age int), note that you can still use the older way of doing this; GetByBy(string, int). It's an enhancement of the #751 feature request.
  • MVC: Give controllers the ability to auto-initialize themselves by OnActivate func derives from the new ActivateListener interface, this can be used to perform any custom actions when the app registers the supported Controllers. See mvc/session_controller.go for a good use case.
  • errors.Reporter.AddErr returns true if the error is added to the stack, otherwise false.
  • @ZaniaDeveloper fixed #778 with PR: #779.
  • Add StatusSeeOther at mvc login example for Redirection, reported by @motecshine at #777.
  • Fix DisableVersionChecker configuration field is not being passed correctly when it was true via iris.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...}) call.

Su, 01 October 2017 | v8.4.4

  • Fix #762 reported by @xkylsoft
  • Fix #771 reported by @cdren
  • Improvements to the memstore's GetInt, GetInt64, GetFloat64, GetBool and remove the golang/net/context's interface completion from Context, read the changes for more
  • Add two examples for folder structuring as requested at #748
  • Add node.js express benchmarks similar to iris and netcore

We, 27 September 2017 | v8.4.3

Fr, 15 September 2017 | v8.4.2

MVC

Support more than one dynamic method function receivers.

package main

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Controller("/user", new(UserController))
    app.Run(iris.Addr("localhost:8080"))
}

type UserController struct { iris.Controller }

// Maps to GET /user
// Request example: http://localhost:8080/user
// as usual.
func (c *UserController) Get() {
    c.Text = "hello from /user"
}

// Maps to GET /user/{paramfirst:long}
// Request example: http://localhost:8080/user/42
// as usual.
func (c *UserController) GetBy(userID int64) {
    c.Ctx.Writef("hello user with id: %d", userID)
}

// NEW:
// Maps to GET /user/{paramfirst:long}/business/{paramsecond:long}
// Request example: http://localhost:8080/user/42/business/93
func (c *UserController) GetByBusinessBy(userID int64, businessID int64) {
    c.Ctx.Writef("fetch a business id: %d that user with id: %d owns, may make your db query faster",
    businessID, userID)
}

Th, 07 September 2017 | v8.4.1

Routing

Add a macro type for booleans: app.Get("/mypath/{paramName:boolean}", myHandler).

+------------------------+
| {param:boolean}        |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"

Add context.Params().GetBool(paramName string) (bool, error) respectfully.

app := iris.New()
app.Get("/mypath/{has:boolean}", func(ctx iris.Context) { // <--
    // boolean first return value
    // error as second return value
    //
    // error will be always nil here because
    // we use the {has:boolean} so router
    // makes sure that the parameter is a boolean
    // otherwise it will return a 404 not found http error code
    // skipping the call of this handler.
    has, _ := ctx.Params().GetBool("has") // <--
    if has {
        ctx.HTML("<strong>it's true</strong>")
    }else {
        ctx.HTML("<strong>it's false</string>")
    }
})
// [...]

MVC

Support for boolean method receivers, i.e GetBy(bool), PostBy(bool)....

app := iris.New()

app.Controller("/equality", new(Controller))
type Controller struct {
    iris.Controller
}

// handles the "/equality" path.
func (c *Controller) Get() {

}

// registers and handles the path: "/equality/{param:boolean}".
func (c *Controller) GetBy(is bool) { // <--
    // [...]
}

Supported types for method functions receivers are: int, int64, bool and string.

Su, 27 August 2017 | v8.4.0

Miscellaneous

Router

Add a new macro type for path parameters, long, it's the go type int64.

app.Get("/user/{id:long}", func(ctx context.Context) {
	userID, _ := ctx.Params().GetInt64("id")
})

MVC

The ability to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that after a go get -u github.com/kataras/iris you will be able to use things like these:

If app.Controller("/user", new(user.Controller))

  • func(*Controller) Get() - GET:/user , as usual.
  • func(*Controller) Post() - POST:/user, as usual.
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

If app.Controller("/profile", new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

If app.Controller("/assets", new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

Example can be found at: _examples/mvc/login/user/controller.go.

Pretty awesome, right?

We, 23 August 2017 | v8.3.4

Give read access to the current request context's route, a feature that many of you asked a lot.

func(ctx context.Context) {
	_ = ctx.GetCurrentRoute().Name()
	//					.Method() returns string, same as ctx.Method().
	//					.Subdomain() returns string, the registered subdomain.
	//					.Path() returns string, the registered path.
	//					.IsOnline() returns boolean.
}
type MyController struct {
	mvc.Controller
}

func (c *MyController) Get(){
	_ = c.Route().Name() // same as `c.Ctx.GetCurrentRoute().Name()`.
	// [...]
}

Updated: 24 August 2017

This evening, on the next version 8.3.5:

Able to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that in the future you will be able to use something like these:

If app.Controller("/user", new(user.Controller))

  • func(c *Controller) Get() - GET:/user , as usual.
  • func(c *Controller) Post() - POST:/user, as usual.
  • func(c *Controller) GetLogin() - GET:/user/login
  • func(c *Controller) PostLogin() - POST:/user/login
  • func(c *Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(c *Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(c *Controller) GetBy() - GET:/user/{param}
  • func(c *Controller) GetByName(name string) - GET:/user/{name}
  • func(c *Controller) PostByName(name string) - POST:/user/{name}
  • func(c *Controller) GetByID(id int64 || int) - GET:/user/{id:int}
  • func(c *Controller) PostByID(id int64 || int) - POST:/user/{id:int}

Watch and stay tuned my friends.

We, 23 August 2017 | v8.3.3

Better debug messages when using MVC.

Add support for recursively binding and custom controllers embedded to other custom controller, that's the new feature. That simply means that Iris users are able to use "shared" controllers everywhere; when binding, using models, get/set persistence data, adding middleware, intercept request flow.

This will help web authors to split the logic at different controllers. Those controllers can be also used as "standalone" to serve a page somewhere else in the application as well.

My personal advice to you is to always organize and split your code nicely and wisely in order to avoid using such as an advanced MVC feature, at least any time soon.

I'm aware that this is not always an easy task to do, therefore is here if you ever need it :)

A ridiculous simple example of this feature can be found at the mvc/controller_test.go file.

Tu, 22 August 2017 | v8.3.2

MVC

When one or more values of handler type (func(ctx context.Context)) are passed
right to the controller initialization then they will be recognised and act as middleware(s)
that ran even before the controller activation, there is no reason to load
the whole controller if the main handler or its BeginRequest are not "allowed" to be executed.

Example Code

func checkLogin(ctx context.Context) {
	if !myCustomAuthMethodPassed {
		// [set a status or redirect, you know what to do]
		ctx.StatusCode(iris.StatusForbidden)
		return
	}

	// [continue to the next handler, at this example is our controller itself]
	ctx.Next()
}

// [...]
app.Controller(new(ProfileController), checkLogin)
// [...]

Usage of these kind of MVC features could be found at the mvc/controller_test.go file.

Other minor enhancements

  • fix issue #726*
  • fix redis sessiondb expiration*
  • update recursively when new version is available*
  • some minor session enhancements*

Sa, 19 August 2017 | v8.3.1

First of all I want to thank you for the 100% green feedback you gratefully sent me you about
my latest article Go vs .NET Core in terms of HTTP performance, published at medium's hackernoon.com and dev.to. I really appreciate it💓

No API Changes.

However two more methods added to the Controller.

  • RelPath() string, returns the relative path based on the controller's name and the request path.
  • RelTmpl() string, returns the relative template directory based on the controller's name.

These are useful when dealing with big controllers, they help you to keep align with any
future changes inside your application.

Let's refactor our ProfileController enhancemed by these two new functions.

func (pc *ProfileController) tmpl(relativeTmplPath string) {
	// the relative template files directory of this controller.
	views := pc.RelTmpl()
	pc.Tmpl = views + relativeTmplPath
}

func (pc *ProfileController) match(relativeRequestPath string) bool {
	// the relative request path of this controller.
	path := pc.RelPath()
	return path == relativeRequestPath
}

func (pc *ProfileController) Get() {
	// requested: "/profile"
	// so relative path is "/" because of the ProfileController.
	if pc.match("/") {

		// views/profile/index.html
		pc.tmpl("index.html")
		return
	}

	// requested: "/profile/browse"
	// so relative path is "/browse".
	if pc.match("/browse") {
		pc.Path = "/profile"
		return
	}

	// requested: "/profile/me"
	// so the relative path is "/me"
	if pc.match("/me") {
		
		// views/profile/me.html
		pc.tmpl("me.html")
		return
	}

	// requested: "/profile/$ID"
	// so the relative path is "/$ID"
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound

		// views/profile/notfound.html
		pc.tmpl("notfound.html")
		pc.Data["ID"] = id
		return
	}

	// views/profile/profile.html
	pc.tmpl("profile.html")
	pc.User = user
}

Want to learn more about these functions? Go to the mvc/controller_test.go file and scroll to the bottom!

Fr, 18 August 2017 | v8.3.0

Good news for devs that are used to write their web apps using the MVC architecture pattern.

Implement a whole new mvc package with additional support for models and easy binding.

@kataras started to develop that feature by version 8.2.5, back then it didn't seem
to be a large feature and maybe a game-changer, so it lived inside the kataras/iris/core/router/controller.go file.
However with this version, so many things are implemented for the MVC and we needed a new whole package,
this new package is the kataras/iris/mvc, but if you used go 1.9 to build then you don't have to do any refactor, you could use the iris.Controller type alias.

People who used the mvc from its baby steps(v8.2.5) the only syntactic change you'll have to do is to rename the router.Controller to mvc.Controller:

Before:

import "github.com/kataras/iris/core/router"
type MyController struct {
    router.Controller
}

Now:

import "github.com/kataras/iris/mvc"
type MyController struct {
    mvc.Controller
    // if you build with go1.9 you can omit the import of mvc package
    // and just use `iris.Controller` instead.
}

MVC (Model View Controller)

From version 8.3 and after Iris has first-class support for the MVC pattern, you'll not find
these stuff anywhere else in the Go world.

Example Code

package main

import (
	"sync"

	"github.com/kataras/iris"
	"github.com/kataras/iris/mvc"
)

func main() {
	app := iris.New()
	app.RegisterView(iris.HTML("./views", ".html"))

	// when we have a path separated by spaces
	// then the Controller is registered to all of them one by one.
	//
	// myDB is binded to the controller's `*DB` field: use only structs and pointers.
	app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
		new(ProfileController), myDB) // IMPORTANT

	app.Run(iris.Addr(":8080"))
}

// UserModel our example model which will render on the template.
type UserModel struct {
	ID       int64
	Username string
}

// DB is our example database.
type DB struct {
	usersTable map[int64]UserModel
	mu         sync.RWMutex
}

// GetUserByID imaginary database lookup based on user id.
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
	db.mu.RLock()
	u, found = db.usersTable[id]
	db.mu.RUnlock()
	return
}

var myDB = &DB{
	usersTable: map[int64]UserModel{
		1:  {1, "kataras"},
		2:  {2, "makis"},
		42: {42, "jdoe"},
	},
}

// ProfileController our example user controller which controls
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
type ProfileController struct {
	mvc.Controller // IMPORTANT

	User UserModel `iris:"model"`
	// we will bind it but you can also tag it with`iris:"persistence"`
	// and init the controller with manual &PorifleController{DB: myDB}.
	DB *DB
}

// Get method handles all "GET" HTTP Method requests of the controller's paths.
func (pc *ProfileController) Get() { // IMPORTANT
	path := pc.Path

	// requested: /profile path
	if path == "/profile" {
		pc.Tmpl = "profile/index.html"
		return
	}
	// requested: /profile/browse
	// this exists only to proof the concept of changing the path:
	// it will result to a redirection.
	if path == "/profile/browse" {
		pc.Path = "/profile"
		return
	}

	// requested: /profile/me path
	if path == "/profile/me" {
		pc.Tmpl = "profile/me.html"
		return
	}

	// requested: /profile/$ID
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound
		pc.Tmpl = "profile/notfound.html"
		pc.Data["ID"] = id
		return
	}

	pc.Tmpl = "profile/profile.html"
	pc.User = user
}


/*
func (pc *ProfileController) Post() {}
func (pc *ProfileController) Put() {}
func (pc *ProfileController) Delete() {}
func (pc *ProfileController) Connect() {}
func (pc *ProfileController) Head() {}
func (pc *ProfileController) Patch() {}
func (pc *ProfileController) Options() {}
func (pc *ProfileController) Trace() {}
*/

/*
func (pc *ProfileController) All() {}
//        OR
func (pc *ProfileController) Any() {}
*/

Iris web framework supports Request data, Models, Persistence Data and Binding
with the fastest possible execution.

Characteristics

All HTTP Methods are supported, for example if want to serve GET
then the controller should have a function named Get(),
you can define more than one method function to serve in the same Controller struct.

Persistence data inside your Controller struct (share data between requests)
via iris:"persistence" tag right to the field or Bind using app.Controller("/" , new(myController), theBindValue).

Models inside your Controller struct (set-ed at the Method function and rendered by the View)
via iris:"model" tag right to the field, i.e User UserModel `iris:"model" name:"user"` view will recognise it as {{.user}}.
If name tag is missing then it takes the field's name, in this case the "User".

Access to the request path and its parameters via the Path and Params fields.

Access to the template file that should be rendered via the Tmpl field.

Access to the template data that should be rendered inside
the template file via Data field.

Access to the template layout via the Layout field.

Access to the low-level context.Context via the Ctx field.

Get the relative request path by using the controller's name via RelPath().

Get the relative template path directory by using the controller's name via RelTmpl().

Flow as you used to, Controllers can be registered to any Party,
including Subdomains, the Party's begin and done handlers work as expected.

Optional BeginRequest(ctx) function to perform any initialization before the method execution,
useful to call middlewares or when many methods use the same collection of data.

Optional EndRequest(ctx) function to perform any finalization after any method executed.

Inheritance, recursively, see for example our mvc.SessionController, it has the mvc.Controller as an embedded field
and it adds its logic to its BeginRequest, here.

Read access to the current route via the Route field.

Using Iris MVC for code reuse

By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.

If you're new to back-end web development read about the MVC architectural pattern first, a good start is that wikipedia article.

Follow the examples below,

Bugs

Fix #723 reported by @speedwheel.

Mo, 14 August 2017 | v8.2.6

Able to call done/end handlers inside a Controller, via optional EndRequest(ctx context.Context) function inside the controller struct.

// it's called after t.Get()/Post()/Put()/Delete()/Connect()/Head()/Patch()/Options()/Trace().
func (t *testControllerEndRequestFunc) EndRequest(ctx context.Context) {
    // 2.
    // [your code goes here...]
}

// will handle "GET" request HTTP method only.
func (t *testControllerEndRequestFunc) Get() {
    // 1.
    // [your code goes here...]
}

Look at the v8.2.5 changelog to learn more about the new Iris Controllers feature.

Su, 13 August 2017 | v8.2.5

Good news for devs that are used to write their web apps using the MVC-style app architecture.

Yesterday I wrote a tutorial on how you can transform your raw Handlers to Controllers using the existing tools only (Iris is the most modular web framework out there, we all have no doubt about this).

Today, I did implement the Controller idea as built'n feature inside Iris.
Our Controller supports many things among them are:

  • all HTTP Methods are supported, for example if want to serve GET then the controller should have a function named Get(), you can define more than one method function to serve in the same Controller struct
  • persistence data inside your Controller struct (share data between requests) via iris:"persistence" tag right to the field
  • optional BeginRequest(ctx) function to perform any initialization before the methods, useful to call middlewares or when many methods use the same collection of data
  • optional EndRequest(ctx) function to perform any finalization after the methods executed
  • access to the request path parameters via the Params field
  • access to the template file that should be rendered via the Tmpl field
  • access to the template data that should be rendered inside the template file via Data field
  • access to the template layout via the Layout field
  • access to the low-level context.Context via the Ctx field
  • flow as you used to, Controllers can be registered to any Party, including Subdomains, the Party's begin and done handlers work as expected.

It's very easy to get started, the only function you need to call instead of app.Get/Post/Put/Delete/Connect/Head/Patch/Options/Trace is the app.Controller.

Example Code:

// file: main.go

package main

import (
    "github.com/kataras/iris"

    "controllers"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    app.Controller("/", new(controllers.Index))

    // http://localhost:8080/
    app.Run(iris.Addr(":8080"))
}
// file: controllers/index.go

package controllers

import (
    "github.com/kataras/iris/core/router"
)

// Index is our index example controller.
type Index struct {
    mvc.Controller
    // if you're using go1.9: 
    // you can omit the /core/router import statement
    // and just use the `iris.Controller` instead.
}

// will handle GET method on http://localhost:8080/
func (c *Index) Get() {
    c.Tmpl = "index.html"
    c.Data["title"] = "Index page"
    c.Data["message"] = "Hello world!"
}

// will handle POST method on http://localhost:8080/
func (c *Index) Post() {}

Tip: declare a func(c *Index) All() {} or Any() to register all HTTP Methods.

A full example can be found at the _examples/mvc folder.

Sa, 12 August 2017 | v8.2.4

No API Changes.

Fix #717, users are welcomed to follow the thread for any questions or reports about Gzip and Static Files Handlers only.

Th, 10 August 2017 | v8.2.3

No API Changes.

Fix #714

Continue to v8.2.2 for more...

Th, 10 August 2017 | v8.2.2

No API Changes.

  • Implement Google reCAPTCHA middleware, example here
  • Fix kataras/golog prints with colors on windows server 2012 while it shouldn't because its command line tool does not support 256bit colors
  • Improve the updater by a custom self-updated back-end version checker, can be disabled by:
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)

Or

app.Configure(iris.WithoutVersionChecker)

Or

app.Configure(iris.WithConfiguration(iris.Configuration{DisableVersionChecker:true}))

Tu, 08 August 2017 | v8.2.1

No API Changes. Great news for the unique iris sessions library, once again.

NEW: LevelDB-based session database implemented, example here.

Redis-based sessiondb has no longer the MaxAgeSeconds config field,
this is passed automatically by the session manager, now.

All sessions databases have an Async(bool) function, if turned on
then all synchronization between the memory store and the back-end database will happen
inside different go routines. By-default async is false but it's recommended to turn it on, it will make sessions to be stored faster, at most.

All reported issues have been fixed, the API is simplified by v8.2.0 so everyone can
create and use any back-end storage for application's sessions persistence.

Mo, 07 August 2017 | v8.2.0

No Common-API Changes.

Good news for iris sessions back-end databases users.

Info for session database authors Session Database API Changed to:
type Database interface {
	Load(sid string) RemoteStore
	Sync(p SyncPayload)
}

// SyncPayload reports the state of the session inside a database sync action.
type SyncPayload struct {
	SessionID string

	Action Action
	// on insert it contains the new key and the value
	// on update it contains the existing key and the new value
	// on delete it contains the key (the value is nil)
	// on clear it contains nothing (empty key, value is nil)
	// on destroy it contains nothing (empty key, value is nil)
	Value memstore.Entry
	// Store contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Store RemoteStore
}


// RemoteStore is a helper which is a wrapper
// for the store, it can be used as the session "table" which will be
// saved to the session database.
type RemoteStore struct {
	// Values contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Values memstore.Store
	// on insert it contains the expiration datetime
	// on update it contains the new expiration datetime(if updated or the old one)
	// on delete it will be zero
	// on clear it will be zero
	// on destroy it will be zero
	Lifetime LifeTime
}

Read more at sessions/database.go, view how three built'n session databases are being implemented here.

All sessions databases are updated and they performant even faster than before.

  • NEW raw file-based session database implemented, example here
  • NEW boltdb-based session database implemented, example here (recommended as it's safer and faster)
  • redis sessiondb updated to the latest api

Under the cover, session database works entirely differently than before but nothing changed from the user's perspective, so upgrade with go get -u github.com/kataras/iris and sleep well.

Tu, 01 August 2017 | v8.1.3

  • Add Option function to the html view engine: #694
  • Fix sessions backend databases restore expiration: #692 by @corebreaker
  • Add PartyFunc, same as Party but receives a function with the sub router as its argument instead [GO1.9 Users-ONLY]

Mo, 31 July 2017 | v8.1.2

Add a ConfigureHost function as an alternative way to customize the hosts via host.Configurator.
The first way was to pass host.Configurator as optional arguments on iris.Runners built'n functions (iris#Server, iris#Listener, iris#Addr, iris#TLS, iris#AutoTLS), example of this can be found there.

Example Code:

package main

import (
	stdContext "context"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/host"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx context.Context) {
		ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
	})

    app.ConfigureHost(configureHost) // or pass "configureHost" as `app.Addr` argument, same result.

	app.Logger().Info("Wait 10 seconds and check your terminal again")
	// simulate a shutdown action here...
	go func() {
		<-time.After(10 * time.Second)
		timeout := 5 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		// close all hosts, this will notify the callback we had register
		// inside the `configureHost` func.
		app.Shutdown(ctx)
	}()

	// http://localhost:8080
	// wait 10 seconds and check your terminal.
	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func configureHost(su *host.Supervisor) {
	// here we have full access to the host that will be created
	// inside the `app.Run` or `app.NewHost` function .
	//
	// we're registering a shutdown "event" callback here:
	su.RegisterOnShutdown(func() {
		println("server is closed")
	})
	// su.RegisterOnError
	// su.RegisterOnServe
}

Su, 30 July 2017

Greetings my friends, nothing special today, no version number yet.

We just improve the, external, Iris Logging library and the Columns config field from middleware/logger defaults to false now. Upgrade with go get -u github.com/kataras/iris and have fun!

Sa, 29 July 2017 | v8.1.1

No breaking changes, just an addition to make your life easier.

This feature has been implemented after @corebreaker 's request, posted at: #688. He was also tried to fix that by a PR, we thanks him but the problem with that PR was the duplication and the separation of concepts, however we thanks him for pushing for a solution. The current feature's implementation gives a permant solution to host supervisor access issues.

Optional host configurators added to all common serve and listen functions.

Below you'll find how to gain access to the host, the second way is the new feature.

Hosts

Access to all hosts that serve your application can be provided by
the Application#Hosts field, after the Run method.

But the most common scenario is that you may need access to the host before the Run method,
there are two ways of gain access to the host supervisor, read below.

First way is to use the app.NewHost to create a new host
and use one of its Serve or Listen functions
to start the application via the iris#Raw Runner.
Note that this way needs an extra import of the net/http package.

Example Code:

h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){
    println("server was closed!")
})

app.Run(iris.Raw(h.ListenAndServe))

Second, and probably easier way is to use the host.Configurator.

Note that this method requires an extra import statement of
"github.com/kataras/iris/core/host" when using go < 1.9,
if you're targeting on go1.9 then you can use the iris#Supervisor
and omit the extra host import.

All common Runners we saw earlier (iris#Addr, iris#Listener, iris#Server, iris#TLS, iris#AutoTLS)
accept a variadic argument of host.Configurator, there are just func(*host.Supervisor).
Therefore the Application gives you the rights to modify the auto-created host supervisor through these.

Example Code:

package main

import (
    stdContext "context"
    "time"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
    "github.com/kataras/iris/core/host"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
        ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
    })

    app.Logger().Info("Wait 10 seconds and check your terminal again")
    // simulate a shutdown action here...
    go func() {
        <-time.After(10 * time.Second)
        timeout := 5 * time.Second
        ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
        defer cancel()
        // close all hosts, this will notify the callback we had register
        // inside the `configureHost` func.
        app.Shutdown(ctx)
    }()

    // start the server as usual, the only difference is that
    // we're adding a second (optional) function
    // to configure the just-created host supervisor.
    //
    // http://localhost:8080
    // wait 10 seconds and check your terminal.
    app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed))

}

func configureHost(su *host.Supervisor) {
    // here we have full access to the host that will be created
    // inside the `Run` function.
    //
    // we register a shutdown "event" callback
    su.RegisterOnShutdown(func() {
        println("server is closed")
    })
    // su.RegisterOnError
    // su.RegisterOnServe
}

Read more about listening and gracefully shutdown by navigating to: https://github.com/kataras/iris/tree/master/_examples/#http-listening

We, 26 July 2017 | v8.1.0

The app.Logger() *logrus.Logger was replaced with a custom implementation [golog], it's compatible with the logrus package and other open-source golang loggers as well, because of that: #680 (comment).

The API didn't change much except these:

  • the new implementation does not recognise Fatal and Panic because, actually, iris never panics
  • the old app.Logger().Out = io.Writer should be written as app.Logger().SetOutput(io.Writer)

The new implementation, golog is featured, three times faster than logrus
and it completes every common usage.

Integration

I understand that many of you may use logrus outside of Iris too. To integrate an external logrus logger just
Install it-- all print operations will be handled by the provided logrus instance.

import (
    "github.com/kataras/iris"
    "github.com/sirupsen/logrus"
)

package main(){
    app := iris.New()
    app.Logger().Install(logrus.StandardLogger()) // the package-level logrus instance
    // [...]
}

For more information about our new logger please navigate to: https://github.com/kataras/golog - contributions are welcomed as well!

Sa, 23 July 2017 | v8.0.7

Fix It's true that with UseGlobal the "/path1.txt" route call the middleware but cause the prepend, the order is inversed

Sa, 22 July 2017 | v8.0.5 & v8.0.6

No API Changes.

Performance

Add an experimental Configuration#EnableOptimizations option.

type Configuration {
    // [...]

    // EnableOptimization when this field is true
    // then the application tries to optimize for the best performance where is possible.
    //
    // Defaults to false.
    EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"`

    // [...]
}

Usage:

app.Run(iris.Addr(":8080"), iris.WithOptimizations)

Django view engine

@corebreaker pushed a PR to solve the Problem for {%extends%} in Django Engine with embedded files.

Logger

Remove the vendor/github.com/sirupsen/logrus folder, as a temporary solution for the #680 (comment).

Future versions

The logrus will be replaced with a custom implementation, because of that: #680 (comment).

As far as we know, @kataras is working on this new implementation, see here,
which will be compatible with the logrus package and other open-source golang loggers as well.

Mo, 17 July 2017 | v8.0.4

No API changes.

HTTP Errors

Fix a rare behavior: error handlers are not executed correctly
when a before-handler by-passes the order of execution, relative to the previous feature.

Request Logger

Add Configuration#MessageContextKey. Example can be found at _examples/http_request/request-logger/main.go.

Su, 16 July 2017 | v8.0.3

No API changes.

Relative issues:

HTTP Errors

Able to register a chain of Handlers (and middleware with ctx.Next() support like routes) for a specific error code, read more at issues/674. Usage example can be found at _examples/http_request/request-logger/main.go.

New function to register a Handler or a chain of Handlers for all official http error codes, by calling the new app.OnAnyErrorCode(func(ctx context.Context){}), read more at issues/675. Usage example can be found at _examples/http_request/request-logger/main.go.

Request Logger

Add Configuration#LogFunc and Configuration#Columns fields, read more at issues/676. Example can be found at _examples/http_request/request-logger/request-logger-file/main.go.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Sa, 15 July 2017 | v8.0.2

Okay my friends, this is a good time to upgrade, I did implement a feature that you were asking many times at the past.

Iris' router can now handle root-level wildcard paths app.Get("/{paramName:path}).

In case you're wondering: no it does not conflict with other static or dynamic routes, meaning that you can code something like this:

// it isn't conflicts with the rest of the static routes or dynamic routes with a path prefix.
app.Get("/{pathParamName:path}", myHandler) 

Or even like this:

package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
)

func main() {
	app := iris.New()

	// this works as expected now,
	// will handle all GET requests
	// except:
	// /                     -> because of app.Get("/", ...)
	// /other/anything/here  -> because of app.Get("/other/{paramother:path}", ...)
	// /other2/anything/here -> because of app.Get("/other2/{paramothersecond:path}", ...)
	// /other2/static        -> because of app.Get("/other2/static", ...)
	//
	// It isn't conflicts with the rest of the routes, without routing performance cost!
	//
	// i.e /something/here/that/cannot/be/found/by/other/registered/routes/order/not/matters
	app.Get("/{p:path}", h)

	// this will handle only GET /
	app.Get("/", staticPath)

	// this will handle all GET requests starting with "/other/"
	//
	// i.e /other/more/than/one/path/parts
	app.Get("/other/{paramother:path}", other)

	// this will handle all GET requests starting with "/other2/"
	// except /other2/static (because of the next static route)
	//
	// i.e /other2/more/than/one/path/parts
	app.Get("/other2/{paramothersecond:path}", other2)

	// this will handle only GET /other2/static
	app.Get("/other2/static", staticPath)

	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func h(ctx context.Context) {
	param := ctx.Params().Get("p")
	ctx.WriteString(param)
}

func other(ctx context.Context) {
	param := ctx.Params().Get("paramother")
	ctx.Writef("from other: %s", param)
}

func other2(ctx context.Context) {
	param := ctx.Params().Get("paramothersecond")
	ctx.Writef("from other2: %s", param)
}

func staticPath(ctx context.Context) {
	ctx.Writef("from the static path: %s", ctx.Path())
}

If you find any bugs with this change please send me a chat message in order to investigate it, I'm totally free at weekends.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Th, 13 July 2017 | v8.0.1

Nothing tremendous at this minor version.

We've just added a configuration field in order to ignore errors received by the Run function, see below.

Configuration#IgnoreServerErrors

type Configuration struct {
    // [...]

    // IgnoreServerErrors will cause to ignore the matched "errors"
    // from the main application's `Run` function.
    // This is a slice of string, not a slice of error
    // users can register these errors using yaml or toml configuration file
    // like the rest of the configuration fields.
    //
    // See `WithoutServerError(...)` function too.
    //
    // Defaults to an empty slice.
    IgnoreServerErrors []string `yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`

    // [...]
}

Configuration#WithoutServerError

// WithoutServerError will cause to ignore the matched "errors"
// from the main application's `Run` function.
//
// Usage:
// err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
//
// See `Configuration#IgnoreServerErrors []string` too.
WithoutServerError(errors ...error) Configurator

By default no error is being ignored, of course.

Example code:
_examples/http-listening/listen-addr/omit-server-errors

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
    	ctx.HTML("<h1>Hello World!/</h1>")
    })

    err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    if err != nil {
        // do something
    }
    // same as:
    // err := app.Run(iris.Addr(":8080"))
    // if err != nil && (err != iris.ErrServerClosed || err.Error() != iris.ErrServerClosed.Error()) {
    //     [...]
    // }
}

At first we didn't want to implement something like that because it's ridiculous easy to do it manually but a second thought came to us,
that many applications are based on configuration, therefore it would be nice to have something to ignore errors
by simply string values that can be passed to the application's configuration via toml or yaml files too.

This feature has been implemented after a request of ignoring the iris/http#ErrServerClosed from the Run function:
#668

Mo, 10 July 2017 | v8.0.0

📈 One and a half years with Iris and You...

Despite the deflamations, the clickbait articles, the removed posts of mine at reddit/r/golang, the unexpected and inadequate ban from the gophers slack room by @dlsniper alone the previous week without any reason or inform, Iris is still here and will be.

  • 7070 github stars
  • 749 github forks
  • 1m total views at its documentation
  • ~800$ at donations (there're a lot for a golang open-source project, thanks to you)
  • ~550 reported bugs fixed
  • ~30 community feature requests have been implemented

🔥 Reborn

As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore.

After a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community.

The leadership of this, open-source, repository was transferred to hiveminded, the author of iris-based get-ion/ion, he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s).

These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me!

📰 Changelog

app. = app := iris.New(); app.

ctx. = func(ctx context.Context) { ctx. }

Docker

Docker and kubernetes integration showcase, see the iris-contrib/cloud-native-go repository as an example.

Logger

  • Logger which was an io.Writer was replaced with the pluggable logrus.
    • which you still attach an io.Writer with app.Logger().Out = an io.Writer.
    • iris as always logs only critical errors, you can disable them with app.Logger().Level = iris.NoLog
    • the request logger outputs the incoming requests as INFO level.

Sessions

Remove ctx.Session() and app.AttachSessionManager, devs should import and use the sessions package as standalone, it's totally optional, devs can use any other session manager too. Examples here.

Websockets

The github.com/kataras/iris/websocket package does not handle the endpoint and client side automatically anymore. Example code:

func setupWebsocket(app *iris.Application) {
    // create our echo websocket server
    ws := websocket.New(websocket.Config{
    	ReadBufferSize:  1024,
    	WriteBufferSize: 1024,
    })
    ws.OnConnection(handleConnection)
    // serve the javascript built'n client-side library,
    // see weboskcets.html script tags, this path is used.
    app.Any("/iris-ws.js", func(ctx context.Context) {
    	ctx.Write(websocket.ClientSource)
    })

    // register the server on an endpoint.
    // see the inline javascript code in the websockets.html, this endpoint is used to connect to the server.
    app.Get("/echo", ws.Handler())
}

More examples here

View

Rename app.AttachView(...) to app.RegisterView(...).

Users can omit the import of github.com/kataras/iris/view and use the github.com/kataras/iris package to
refer to the view engines, i.e: app.RegisterView(iris.HTML("./templates", ".html")) is the same as import "github.com/kataras/iris/view" [...] app.RegisterView(view.HTML("./templates" ,".html")).

Examples here

Security

At previous versions, when you called ctx.Remoteaddr() Iris could parse and return the client's IP from the "X-Real-IP", "X-Forwarded-For" headers. This was a security leak as you can imagine, because the user can modify them. So we've disabled these headers by-default and add an option to add/remove request headers that are responsible to parse and return the client's real IP.

// WithRemoteAddrHeader enables or adds a new or existing request header name
// that can be used to validate the client's real IP.
//
// Existing values are:
// "X-Real-Ip":             false,
// "X-Forwarded-For":       false,
// "CF-Connecting-IP": false
//
// Look `context.RemoteAddr()` for more.
WithRemoteAddrHeader(headerName string) Configurator // enables a header.
WithoutRemoteAddrHeader(headerName string) Configurator // disables a header.

For example, if you want to enable the "CF-Connecting-IP" header (cloudflare)
you have to add the WithRemoteAddrHeader option to the app.Run function, at the end of your program.

app.Run(iris.Addr(":8080"), iris.WithRemoteAddrHeader("CF-Connecting-IP"))
// This header name will be checked when ctx.RemoteAddr() called and if exists
// it will return the client's IP, otherwise it will return the default *http.Request's `RemoteAddr` field.

Miscellaneous

Fix typescript tools.

_examples folder has been ordered by feature and usage:
- contains tests on some examples
- new examples added, one of them shows how the reuseport feature on UNIX and BSD systems can be used to listen for incoming connections, see here

Replace supervisor's tasks with events, like RegisterOnShutdown, RegisterOnError, RegisterOnServe and fix the (unharmful) race condition when output the banner to the console. Global notifier for interrupt signals which can be disabled via app.Run([...], iris.WithoutInterruptHandler), look graceful-shutdown example for more.

More handlers are ported to Iris (they can be used as they are without iris.FromStd), these handlers can be found at iris-contrib/middleware. Feel free to put your own there.

Middleware Description Example
jwt Middleware checks for a JWT on the Authorization header on incoming requests and decodes it. iris-contrib/middleware/jwt/_example
cors HTTP Access Control. iris-contrib/middleware/cors/_example
secure Middleware that implements a few quick security wins. iris-contrib/middleware/secure/_example
tollbooth Generic middleware to rate-limit HTTP requests. iris-contrib/middleware/tollbooth/_examples/limit-handler
cloudwatch AWS cloudwatch metrics middleware. iris-contrib/middleware/cloudwatch/_example
new relic Official New Relic Go Agent. iris-contrib/middleware/newrelic/_example
prometheus Easily create metrics endpoint for the prometheus instrumentation tool iris-contrib/middleware/prometheus/_example

v7.x is deprecated because it sold as it is and it is not part of the public, stable gopkg.in iris versions. Developers/users of this library should upgrade their apps to v8.x, the refactor process will cost nothing for most of you, as the most common API remains as it was. The changelog history from that are being presented below.

Th, 15 June 2017 | v7.2.0

About our new home page

https://iris-go.com

Thanks to Santosh Anand the https://iris-go.com has been upgraded and it's really awesome!

Santosh is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.

The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!

Cache

Declare the iris.Cache alias to the new, improved and most-suited for common usage, cache.Handler function.

iris.Cache be used as middleware in the chain now, example here. However you can still use the cache as a wrapper by importing the github.com/kataras/iris/cache package.

File server

  • Fix that.

  • app.StaticHandler(requestPath string, systemPath string, showList bool, gzip bool) -> app.StaticHandler(systemPath,showList bool, gzip bool)

  • New feature for Single Page Applications, app.SPA(assetHandler context.Handler) implemented.

  • New app.StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) added in order to be able to pass that on app.SPA(app.StaticEmbeddedHandler("./public", Asset, AssetNames)).

  • Fix app.StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string).

Examples:

app.StaticWeb doesn't works for root request path "/" anymore, use the new app.SPA instead.

WWW subdomain entry

  • Example added to copy all application's routes, including parties, to the www.mydomain.com

Wrapping the Router

  • Example added to show you how you can use the app.WrapRouter
    to implement a similar to app.SPA functionality, don't panic, it's easier than it sounds.

Testing

  • httptest.New(app *iris.Application, t *testing.T) -> httptest.New(t *testing.T, app *iris.Application).

  • New httptest.NewLocalListener() net.Listener added.

  • New httptest.NewLocalTLSListener(tcpListener net.Listener) net.Listener added.

Useful for testing tls-enabled servers:

Proxies are trying to understand local addresses in order to allow InsecureSkipVerify.

  • host.ProxyHandler(target *url.URL) *httputil.ReverseProxy.

  • host.NewProxy(hostAddr string, target *url.URL) *Supervisor.

    Tests here.

Tu, 13 June 2017 | v7.1.1

Fix that.

Mo, 12 June 2017 | v7.1.0

Fix that.

Su, 11 June 2017 | v7.0.5

Iris now supports static paths and dynamic paths for the same path prefix with zero performance cost:

app.Get("/profile/{id:int}", handler) and app.Get("/profile/create", createHandler) are not in conflict anymore.

The rest of the special Iris' routing features, including static & wildcard subdomains are still work like a charm.

This was one of the most popular community's feature requests. Click here to see a trivial example.

Sa, 10 June 2017 | v7.0.4

  • Simplify and add a test for the basicauth middleware, no need to be
    stored inside the Context anymore, developers can get the validated user(username and password) via context.Request().BasicAuth(). basicauth.Config.ContextKey was removed, just remove that field from your configuration, it's useless now.

Sa, 10 June 2017 | v7.0.3

  • New context.Session().PeekFlash("key") added, unlike GetFlash this will return the flash value but keep the message valid for the next requests too.
  • Complete the httptest example.
  • Fix the (marked as deprecated) ListenLETSENCRYPT function.
  • Upgrade the iris-contrib/middleware including JWT, CORS and Secure handlers.
  • Add OAuth2 example -- showcases the third-party package goth integration with Iris.

Community

Th, 08 June 2017 | v7.0.2

  • Able to set immutable data on sessions and context's storage. Aligned to fix an issue on slices and maps as reported here.

We, 07 June 2017 | v7.0.1

  • Proof of concept of an internal release generator, navigate here to read more.
  • Remove tray icon "feature", click here to learn why.

Sa, 03 June 2017

After 2+ months of hard work and collaborations, Iris version 7 was published earlier today.

If you're new to Iris you don't have to read all these, just navigate to the updated examples and you should be fine:)

Note that this section will not
cover the internal changes, the difference is so big that anybody can see them with a glimpse, even the code structure itself.

Changes from v6

The whole framework was re-written from zero but I tried to keep the most common public API that iris developers use.

Vendoring /w update

The previous vendor action for v6 was done by-hand, now I'm using the go dep tool, I had to do
some small steps:

  • remove files like testdata to reduce the folder size
  • rollback some of the "golang/x/net/ipv4" and "ipv6" source files because they are downloaded to their latest versions
    by go dep, but they had lines with the typealias feature, which is not ready by current golang version (it will be on August)
  • fix "cannot use internal package" at golang/x/net/ipv4 and ipv6 packages
    • rename the interal folder to was-internal, everywhere and fix its references.
  • fix "main redeclared in this block"
    • remove all examples folders.
  • remove main.go files on jsondiff lib, used by gavv/httpexpect, produces errors on test -v ./... while jd and jp folders are not used at all.

The go dep tool does what is says, as expected, don't be afraid of it now.
I am totally recommending this tool for package authors, even if it's in its alpha state.
I remember when Iris was in its alpha state and it had 4k stars on its first weeks/or month and that helped me a lot to fix reported bugs by users and make the framework even better, so give love to go dep from today!

General

  • Several enhancements for the typescript transpiler, view engine, websocket server and sessions manager
  • All Listen methods replaced with a single Run method, see here
  • Configuration, easier to modify the defaults, see here
  • HandlerFunc removed, just Handler of func(context.Context) where context.Context derives from import "github.com/kataras/iris/context" (NEW: this import path is optional, use iris.Context if you've installed Go 1.9)
    • Simplify API, i.e: instead of Handle,HandleFunc,Use,UseFunc,Done,DoneFunc,UseGlobal,UseGlobalFunc use Handle,Use,Done,UseGlobal.
  • Response time decreased even more (9-35%, depends on the application)
  • The Adaptors idea replaced with a more structural design pattern, but you have to apply these changes:
    • app.Adapt(view.HTML/Pug/Amber/Django/Handlebars...) -> app.AttachView(view.HTML/Pug/Amber/Django/Handlebars...)
    • app.Adapt(sessions.New(...)) -> app.AttachSessionManager(sessions.New(...))
    • app.Adapt(iris.LoggerPolicy(...)) -> app.AttachLogger(io.Writer)
    • app.Adapt(iris.RenderPolicy(...)) -> removed and replaced with the ability to replace the whole context with a custom one or override some methods of it, see below.

Routing

  • Remove of multiple routers, now we have the fresh Iris router which is based on top of the julien's httprouter.

    Update 11 June 2017: As of 7.0.5 this is changed, read here.

  • Subdomains routing algorithm has been improved.
  • Iris router is using a custom interpreter with parser and path evaluator to achieve the best expressiveness, with zero performance loss, you ever seen so far, i.e:
    • app.Get("/", "/users/{userid:int min(1)}", handler),
      • {username:string} or just {username}
      • {asset:path},
      • {firstname:alphabetical},
      • {requestfile:file} ,
      • {mylowercaseParam regexp([a-z]+)}.
      • The previous syntax of :param and *param still working as expected. Previous rules for paths confliction remain as they were.
        • Also, path parameter names should be only alphabetical now, numbers and symbols are not allowed (for your own good, I have seen a lot the last year...).

Click here for details.

It was my first attempt/experience on the interpreters field, so be good with it :)

Context

  • iris.Context pointer replaced with context.Context interface as we already mention
    • in order to be able to use a custom context and/or catch lifetime like BeginRequest and EndRequest from context itself, see below
  • context.JSON, context.JSONP, context.XML, context.Markdown, context.HTML work faster
  • context.Render("filename.ext", bindingViewData{}, options) -> context.View("filename.ext")
    • View renders only templates, it will not try to search if you have a restful renderer adapted, because, now, you can do it via method overriding using a custom Context.
    • Able to set context.ViewData and context.ViewLayout via middleware when executing a template.
  • context.SetStatusCode(statusCode) -> context.StatusCode(statusCode)
    • which is equivalent with the old EmitError too:
      • if status code >=400 given can automatically fire a custom http error handler if response wasn't written already.
    • context.StatusCode() -> context.GetStatusCode()
    • app.OnError -> app.OnErrorCode
    • Errors per party are removed by-default, you can just use one global error handler with logic like "if path starts with 'prefix' fire this error handler, else...".
  • Easy way to change Iris' default Context with a custom one, see here
  • context.ResponseWriter().SetBeforeFlush(...) works for Flush and HTTP/2 Push, respectfully
  • Several improvements under the Request transactions
  • Remember that you had to set a status code on each of the render-relative methods? Now it's not required, it just renders
    with the status code that user gave with context.StatusCode or with 200 OK, i.e:
    -context.JSON(iris.StatusOK, myJSON{}) -> context.JSON(myJSON{}).
    • Each one of the context's render methods has optional per-call settings,
    • the new API is even more easier to read, understand and use.

Server

  • Able to set custom underline *http.Server(s) with new Host (aka Server Supervisor) feature
    • Done and Err channels to catch shutdown or any errors on custom hosts,
    • Schedule custom tasks(with cancelation) when server is running, see here
  • Interrupt handler task for gracefully shutdown (when CTRL/CMD+C) are enabled by-default, you can disable its via configuration: app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler)

Future plans

  • Future Go1.9's ServeTLS is ready when 1.9 released
  • Future Go1.9's typealias feature is ready when 1.9 released, i.e context.Context -> iris.Context just one import path instead of todays' two.

v8.5.0

@kataras kataras released this Oct 9, 2017 · 275 commits to master since this release

Su, 09 October 2017 | v8.5.0

MVC

Great news for our MVC Fans or if you're not you may want to use that powerful feature today, because of the smart coding and decisions the performance is quite the same to the pure handlers, see _benchmarks.

Iris now gives you the ability to render a response based on the output values returned method functions!

You can return any value of any type from a method function
and it will be sent to the client as expected.

  • if string then it's the body.
  • if string is the second output argument then it's the content type.
  • if int then it's the status code.
  • if error and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead.
  • if (int, error) and error is not nil then the response result will be the error's text with the status code as int.
  • if custom struct or interface{} or slice or map then it will be rendered as json, unless a string content type is following.
  • if mvc.Result then it executes its Dispatch function, so good design patters can be used to split the model's logic where needed.

The example below is not intended to be used in production but it's a good showcase of some of the return types we saw before;

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/middleware/basicauth"
    "github.com/kataras/iris/mvc"
)

// Movie is our sample data structure.
type Movie struct {
    Name   string `json:"name"`
    Year   int    `json:"year"`
    Genre  string `json:"genre"`
    Poster string `json:"poster"`
}

// movies contains our imaginary data source.
var movies = []Movie{
    {
        Name:   "Casablanca",
        Year:   1942,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/1.jpg",
    },
    {
        Name:   "Gone with the Wind",
        Year:   1939,
        Genre:  "Romance",
        Poster: "https://iris-go.com/images/examples/mvc-movies/2.jpg",
    },
    {
        Name:   "Citizen Kane",
        Year:   1941,
        Genre:  "Mystery",
        Poster: "https://iris-go.com/images/examples/mvc-movies/3.jpg",
    },
    {
        Name:   "The Wizard of Oz",
        Year:   1939,
        Genre:  "Fantasy",
        Poster: "https://iris-go.com/images/examples/mvc-movies/4.jpg",
    },
}


var basicAuth = basicauth.New(basicauth.Config{
    Users: map[string]string{
        "admin": "password",
    },
})


func main() {
    app := iris.New()

    app.Use(basicAuth)

    app.Controller("/movies", new(MoviesController))

    app.Run(iris.Addr(":8080"))
}

// MoviesController is our /movies controller.
type MoviesController struct {
    // mvc.C is just a lightweight lightweight alternative
    // to the "mvc.Controller" controller type,
    // use it when you don't need mvc.Controller's fields
    // (you don't need those fields when you return values from the method functions).
    mvc.C
}

// Get returns list of the movies
// Demo:
// curl -i http://localhost:8080/movies
func (c *MoviesController) Get() []Movie {
    return movies
}

// GetBy returns a movie
// Demo:
// curl -i http://localhost:8080/movies/1
func (c *MoviesController) GetBy(id int) Movie {
    return movies[id]
}

// PutBy updates a movie
// Demo:
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
func (c *MoviesController) PutBy(id int) Movie {
    // get the movie
    m := movies[id]

    // get the request data for poster and genre
    file, info, err := c.Ctx.FormFile("poster")
    if err != nil {
        c.Ctx.StatusCode(iris.StatusInternalServerError)
        return Movie{}
    }
    file.Close()            // we don't need the file
    poster := info.Filename // imagine that as the url of the uploaded file...
    genre := c.Ctx.FormValue("genre")

    // update the poster
    m.Poster = poster
    m.Genre = genre
    movies[id] = m

    return m
}

// DeleteBy deletes a movie
// Demo:
// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1
func (c *MoviesController) DeleteBy(id int) iris.Map {
    // delete the entry from the movies slice
    deleted := movies[id].Name
    movies = append(movies[:id], movies[id+1:]...)
    // and return the deleted movie's name
    return iris.Map{"deleted": deleted}
}

Another good example with a typical folder structure, that many developers are used to work, is located at the new README.md under the Quick MVC Tutorial #3 section.

The complete example source code can be found at _examples/mvc/using-method-result folder.


Upgrade with go get -u -v github.com/kataras/iris or let the auto-updater to do its job.

Fr, 06 October 2017 | v8.4.5

  • Badger team added support for transactions yesterday, therefore the badger session database is updated via 0b48927.
  • MVC: Support more than one path parameters with a single By, when the By keyword is the last word and the func's input arguments are more than one i.e GetBy(name string, age int), note that you can still use the older way of doing this; GetByBy(string, int). It's an enhancement of the #751 feature request.
  • MVC: Give controllers the ability to auto-initialize themselves by OnActivate func derives from the new ActivateListener interface, this can be used to perform any custom actions when the app registers the supported Controllers. See mvc/session_controller.go for a good use case.
  • errors.Reporter.AddErr returns true if the error is added to the stack, otherwise false.
  • @ZaniaDeveloper fixed #778 with PR: #779.
  • Add StatusSeeOther at mvc login example for Redirection, reported by @motecshine at #777.
  • Fix DisableVersionChecker configuration field is not being passed correctly when it was true via iris.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...}) call.

Su, 01 October 2017 | v8.4.4

  • Fix #762 reported by @xkylsoft
  • Fix #771 reported by @cdren
  • Improvements to the memstore's GetInt, GetInt64, GetFloat64, GetBool and remove the golang/net/context's interface completion from Context, read the changes for more
  • Add two examples for folder structuring as requested at #748
  • Add node.js express benchmarks similar to iris and netcore

We, 27 September 2017 | v8.4.3

Fr, 15 September 2017 | v8.4.2

MVC

Support more than one dynamic method function receivers.

package main

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Controller("/user", new(UserController))
    app.Run(iris.Addr("localhost:8080"))
}

type UserController struct { iris.Controller }

// Maps to GET /user
// Request example: http://localhost:8080/user
// as usual.
func (c *UserController) Get() {
    c.Text = "hello from /user"
}

// Maps to GET /user/{paramfirst:long}
// Request example: http://localhost:8080/user/42
// as usual.
func (c *UserController) GetBy(userID int64) {
    c.Ctx.Writef("hello user with id: %d", userID)
}

// NEW:
// Maps to GET /user/{paramfirst:long}/business/{paramsecond:long}
// Request example: http://localhost:8080/user/42/business/93
func (c *UserController) GetByBusinessBy(userID int64, businessID int64) {
    c.Ctx.Writef("fetch a business id: %d that user with id: %d owns, may make your db query faster",
    businessID, userID)
}

Th, 07 September 2017 | v8.4.1

Routing

Add a macro type for booleans: app.Get("/mypath/{paramName:boolean}", myHandler).

+------------------------+
| {param:boolean}        |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"

Add context.Params().GetBool(paramName string) (bool, error) respectfully.

app := iris.New()
app.Get("/mypath/{has:boolean}", func(ctx iris.Context) { // <--
    // boolean first return value
    // error as second return value
    //
    // error will be always nil here because
    // we use the {has:boolean} so router
    // makes sure that the parameter is a boolean
    // otherwise it will return a 404 not found http error code
    // skipping the call of this handler.
    has, _ := ctx.Params().GetBool("has") // <--
    if has {
        ctx.HTML("<strong>it's true</strong>")
    }else {
        ctx.HTML("<strong>it's false</string>")
    }
})
// [...]

MVC

Support for boolean method receivers, i.e GetBy(bool), PostBy(bool)....

app := iris.New()

app.Controller("/equality", new(Controller))
type Controller struct {
    iris.Controller
}

// handles the "/equality" path.
func (c *Controller) Get() {

}

// registers and handles the path: "/equality/{param:boolean}".
func (c *Controller) GetBy(is bool) { // <--
    // [...]
}

Supported types for method functions receivers are: int, int64, bool and string.

Su, 27 August 2017 | v8.4.0

Miscellaneous

Router

Add a new macro type for path parameters, long, it's the go type int64.

app.Get("/user/{id:long}", func(ctx context.Context) {
	userID, _ := ctx.Params().GetInt64("id")
})

MVC

The ability to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that after a go get -u github.com/kataras/iris you will be able to use things like these:

If app.Controller("/user", new(user.Controller))

  • func(*Controller) Get() - GET:/user , as usual.
  • func(*Controller) Post() - POST:/user, as usual.
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

If app.Controller("/profile", new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

If app.Controller("/assets", new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

Example can be found at: _examples/mvc/login/user/controller.go.

Pretty awesome, right?

We, 23 August 2017 | v8.3.4

Give read access to the current request context's route, a feature that many of you asked a lot.

func(ctx context.Context) {
	_ = ctx.GetCurrentRoute().Name()
	//					.Method() returns string, same as ctx.Method().
	//					.Subdomain() returns string, the registered subdomain.
	//					.Path() returns string, the registered path.
	//					.IsOnline() returns boolean.
}
type MyController struct {
	mvc.Controller
}

func (c *MyController) Get(){
	_ = c.Route().Name() // same as `c.Ctx.GetCurrentRoute().Name()`.
	// [...]
}

Updated: 24 August 2017

This evening, on the next version 8.3.5:

Able to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that in the future you will be able to use something like these:

If app.Controller("/user", new(user.Controller))

  • func(c *Controller) Get() - GET:/user , as usual.
  • func(c *Controller) Post() - POST:/user, as usual.
  • func(c *Controller) GetLogin() - GET:/user/login
  • func(c *Controller) PostLogin() - POST:/user/login
  • func(c *Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(c *Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(c *Controller) GetBy() - GET:/user/{param}
  • func(c *Controller) GetByName(name string) - GET:/user/{name}
  • func(c *Controller) PostByName(name string) - POST:/user/{name}
  • func(c *Controller) GetByID(id int64 || int) - GET:/user/{id:int}
  • func(c *Controller) PostByID(id int64 || int) - POST:/user/{id:int}

Watch and stay tuned my friends.

We, 23 August 2017 | v8.3.3

Better debug messages when using MVC.

Add support for recursively binding and custom controllers embedded to other custom controller, that's the new feature. That simply means that Iris users are able to use "shared" controllers everywhere; when binding, using models, get/set persistence data, adding middleware, intercept request flow.

This will help web authors to split the logic at different controllers. Those controllers can be also used as "standalone" to serve a page somewhere else in the application as well.

My personal advice to you is to always organize and split your code nicely and wisely in order to avoid using such as an advanced MVC feature, at least any time soon.

I'm aware that this is not always an easy task to do, therefore is here if you ever need it :)

A ridiculous simple example of this feature can be found at the mvc/controller_test.go file.

Tu, 22 August 2017 | v8.3.2

MVC

When one or more values of handler type (func(ctx context.Context)) are passed
right to the controller initialization then they will be recognised and act as middleware(s)
that ran even before the controller activation, there is no reason to load
the whole controller if the main handler or its BeginRequest are not "allowed" to be executed.

Example Code

func checkLogin(ctx context.Context) {
	if !myCustomAuthMethodPassed {
		// [set a status or redirect, you know what to do]
		ctx.StatusCode(iris.StatusForbidden)
		return
	}

	// [continue to the next handler, at this example is our controller itself]
	ctx.Next()
}

// [...]
app.Controller(new(ProfileController), checkLogin)
// [...]

Usage of these kind of MVC features could be found at the mvc/controller_test.go file.

Other minor enhancements

  • fix issue #726*
  • fix redis sessiondb expiration*
  • update recursively when new version is available*
  • some minor session enhancements*

Sa, 19 August 2017 | v8.3.1

First of all I want to thank you for the 100% green feedback you gratefully sent me you about
my latest article Go vs .NET Core in terms of HTTP performance, published at medium's hackernoon.com and dev.to. I really appreciate it💓

No API Changes.

However two more methods added to the Controller.

  • RelPath() string, returns the relative path based on the controller's name and the request path.
  • RelTmpl() string, returns the relative template directory based on the controller's name.

These are useful when dealing with big controllers, they help you to keep align with any
future changes inside your application.

Let's refactor our ProfileController enhancemed by these two new functions.

func (pc *ProfileController) tmpl(relativeTmplPath string) {
	// the relative template files directory of this controller.
	views := pc.RelTmpl()
	pc.Tmpl = views + relativeTmplPath
}

func (pc *ProfileController) match(relativeRequestPath string) bool {
	// the relative request path of this controller.
	path := pc.RelPath()
	return path == relativeRequestPath
}

func (pc *ProfileController) Get() {
	// requested: "/profile"
	// so relative path is "/" because of the ProfileController.
	if pc.match("/") {

		// views/profile/index.html
		pc.tmpl("index.html")
		return
	}

	// requested: "/profile/browse"
	// so relative path is "/browse".
	if pc.match("/browse") {
		pc.Path = "/profile"
		return
	}

	// requested: "/profile/me"
	// so the relative path is "/me"
	if pc.match("/me") {
		
		// views/profile/me.html
		pc.tmpl("me.html")
		return
	}

	// requested: "/profile/$ID"
	// so the relative path is "/$ID"
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound

		// views/profile/notfound.html
		pc.tmpl("notfound.html")
		pc.Data["ID"] = id
		return
	}

	// views/profile/profile.html
	pc.tmpl("profile.html")
	pc.User = user
}

Want to learn more about these functions? Go to the mvc/controller_test.go file and scroll to the bottom!

Fr, 18 August 2017 | v8.3.0

Good news for devs that are used to write their web apps using the MVC architecture pattern.

Implement a whole new mvc package with additional support for models and easy binding.

@kataras started to develop that feature by version 8.2.5, back then it didn't seem
to be a large feature and maybe a game-changer, so it lived inside the kataras/iris/core/router/controller.go file.
However with this version, so many things are implemented for the MVC and we needed a new whole package,
this new package is the kataras/iris/mvc, but if you used go 1.9 to build then you don't have to do any refactor, you could use the iris.Controller type alias.

People who used the mvc from its baby steps(v8.2.5) the only syntactic change you'll have to do is to rename the router.Controller to mvc.Controller:

Before:

import "github.com/kataras/iris/core/router"
type MyController struct {
    router.Controller
}

Now:

import "github.com/kataras/iris/mvc"
type MyController struct {
    mvc.Controller
    // if you build with go1.9 you can omit the import of mvc package
    // and just use `iris.Controller` instead.
}

MVC (Model View Controller)

From version 8.3 and after Iris has first-class support for the MVC pattern, you'll not find
these stuff anywhere else in the Go world.

Example Code

package main

import (
	"sync"

	"github.com/kataras/iris"
	"github.com/kataras/iris/mvc"
)

func main() {
	app := iris.New()
	app.RegisterView(iris.HTML("./views", ".html"))

	// when we have a path separated by spaces
	// then the Controller is registered to all of them one by one.
	//
	// myDB is binded to the controller's `*DB` field: use only structs and pointers.
	app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
		new(ProfileController), myDB) // IMPORTANT

	app.Run(iris.Addr(":8080"))
}

// UserModel our example model which will render on the template.
type UserModel struct {
	ID       int64
	Username string
}

// DB is our example database.
type DB struct {
	usersTable map[int64]UserModel
	mu         sync.RWMutex
}

// GetUserByID imaginary database lookup based on user id.
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
	db.mu.RLock()
	u, found = db.usersTable[id]
	db.mu.RUnlock()
	return
}

var myDB = &DB{
	usersTable: map[int64]UserModel{
		1:  {1, "kataras"},
		2:  {2, "makis"},
		42: {42, "jdoe"},
	},
}

// ProfileController our example user controller which controls
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
type ProfileController struct {
	mvc.Controller // IMPORTANT

	User UserModel `iris:"model"`
	// we will bind it but you can also tag it with`iris:"persistence"`
	// and init the controller with manual &PorifleController{DB: myDB}.
	DB *DB
}

// Get method handles all "GET" HTTP Method requests of the controller's paths.
func (pc *ProfileController) Get() { // IMPORTANT
	path := pc.Path

	// requested: /profile path
	if path == "/profile" {
		pc.Tmpl = "profile/index.html"
		return
	}
	// requested: /profile/browse
	// this exists only to proof the concept of changing the path:
	// it will result to a redirection.
	if path == "/profile/browse" {
		pc.Path = "/profile"
		return
	}

	// requested: /profile/me path
	if path == "/profile/me" {
		pc.Tmpl = "profile/me.html"
		return
	}

	// requested: /profile/$ID
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound
		pc.Tmpl = "profile/notfound.html"
		pc.Data["ID"] = id
		return
	}

	pc.Tmpl = "profile/profile.html"
	pc.User = user
}


/*
func (pc *ProfileController) Post() {}
func (pc *ProfileController) Put() {}
func (pc *ProfileController) Delete() {}
func (pc *ProfileController) Connect() {}
func (pc *ProfileController) Head() {}
func (pc *ProfileController) Patch() {}
func (pc *ProfileController) Options() {}
func (pc *ProfileController) Trace() {}
*/

/*
func (pc *ProfileController) All() {}
//        OR
func (pc *ProfileController) Any() {}
*/

Iris web framework supports Request data, Models, Persistence Data and Binding
with the fastest possible execution.

Characteristics

All HTTP Methods are supported, for example if want to serve GET
then the controller should have a function named Get(),
you can define more than one method function to serve in the same Controller struct.

Persistence data inside your Controller struct (share data between requests)
via iris:"persistence" tag right to the field or Bind using app.Controller("/" , new(myController), theBindValue).

Models inside your Controller struct (set-ed at the Method function and rendered by the View)
via iris:"model" tag right to the field, i.e User UserModel `iris:"model" name:"user"` view will recognise it as {{.user}}.
If name tag is missing then it takes the field's name, in this case the "User".

Access to the request path and its parameters via the Path and Params fields.

Access to the template file that should be rendered via the Tmpl field.

Access to the template data that should be rendered inside
the template file via Data field.

Access to the template layout via the Layout field.

Access to the low-level context.Context via the Ctx field.

Get the relative request path by using the controller's name via RelPath().

Get the relative template path directory by using the controller's name via RelTmpl().

Flow as you used to, Controllers can be registered to any Party,
including Subdomains, the Party's begin and done handlers work as expected.

Optional BeginRequest(ctx) function to perform any initialization before the method execution,
useful to call middlewares or when many methods use the same collection of data.

Optional EndRequest(ctx) function to perform any finalization after any method executed.

Inheritance, recursively, see for example our mvc.SessionController, it has the mvc.Controller as an embedded field
and it adds its logic to its BeginRequest, here.

Read access to the current route via the Route field.

Using Iris MVC for code reuse

By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.

If you're new to back-end web development read about the MVC architectural pattern first, a good start is that wikipedia article.

Follow the examples below,

Bugs

Fix #723 reported by @speedwheel.

Mo, 14 August 2017 | v8.2.6

Able to call done/end handlers inside a Controller, via optional EndRequest(ctx context.Context) function inside the controller struct.

// it's called after t.Get()/Post()/Put()/Delete()/Connect()/Head()/Patch()/Options()/Trace().
func (t *testControllerEndRequestFunc) EndRequest(ctx context.Context) {
    // 2.
    // [your code goes here...]
}

// will handle "GET" request HTTP method only.
func (t *testControllerEndRequestFunc) Get() {
    // 1.
    // [your code goes here...]
}

Look at the v8.2.5 changelog to learn more about the new Iris Controllers feature.

Su, 13 August 2017 | v8.2.5

Good news for devs that are used to write their web apps using the MVC-style app architecture.

Yesterday I wrote a tutorial on how you can transform your raw Handlers to Controllers using the existing tools only (Iris is the most modular web framework out there, we all have no doubt about this).

Today, I did implement the Controller idea as built'n feature inside Iris.
Our Controller supports many things among them are:

  • all HTTP Methods are supported, for example if want to serve GET then the controller should have a function named Get(), you can define more than one method function to serve in the same Controller struct
  • persistence data inside your Controller struct (share data between requests) via iris:"persistence" tag right to the field
  • optional BeginRequest(ctx) function to perform any initialization before the methods, useful to call middlewares or when many methods use the same collection of data
  • optional EndRequest(ctx) function to perform any finalization after the methods executed
  • access to the request path parameters via the Params field
  • access to the template file that should be rendered via the Tmpl field
  • access to the template data that should be rendered inside the template file via Data field
  • access to the template layout via the Layout field
  • access to the low-level context.Context via the Ctx field
  • flow as you used to, Controllers can be registered to any Party, including Subdomains, the Party's begin and done handlers work as expected.

It's very easy to get started, the only function you need to call instead of app.Get/Post/Put/Delete/Connect/Head/Patch/Options/Trace is the app.Controller.

Example Code:

// file: main.go

package main

import (
    "github.com/kataras/iris"

    "controllers"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    app.Controller("/", new(controllers.Index))

    // http://localhost:8080/
    app.Run(iris.Addr(":8080"))
}
// file: controllers/index.go

package controllers

import (
    "github.com/kataras/iris/core/router"
)

// Index is our index example controller.
type Index struct {
    mvc.Controller
    // if you're using go1.9: 
    // you can omit the /core/router import statement
    // and just use the `iris.Controller` instead.
}

// will handle GET method on http://localhost:8080/
func (c *Index) Get() {
    c.Tmpl = "index.html"
    c.Data["title"] = "Index page"
    c.Data["message"] = "Hello world!"
}

// will handle POST method on http://localhost:8080/
func (c *Index) Post() {}

Tip: declare a func(c *Index) All() {} or Any() to register all HTTP Methods.

A full example can be found at the _examples/mvc folder.

Sa, 12 August 2017 | v8.2.4

No API Changes.

Fix #717, users are welcomed to follow the thread for any questions or reports about Gzip and Static Files Handlers only.

Th, 10 August 2017 | v8.2.3

No API Changes.

Fix #714

Continue to v8.2.2 for more...

Th, 10 August 2017 | v8.2.2

No API Changes.

  • Implement Google reCAPTCHA middleware, example here
  • Fix kataras/golog prints with colors on windows server 2012 while it shouldn't because its command line tool does not support 256bit colors
  • Improve the updater by a custom self-updated back-end version checker, can be disabled by:
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)

Or

app.Configure(iris.WithoutVersionChecker)

Or

app.Configure(iris.WithConfiguration(iris.Configuration{DisableVersionChecker:true}))

Tu, 08 August 2017 | v8.2.1

No API Changes. Great news for the unique iris sessions library, once again.

NEW: LevelDB-based session database implemented, example here.

Redis-based sessiondb has no longer the MaxAgeSeconds config field,
this is passed automatically by the session manager, now.

All sessions databases have an Async(bool) function, if turned on
then all synchronization between the memory store and the back-end database will happen
inside different go routines. By-default async is false but it's recommended to turn it on, it will make sessions to be stored faster, at most.

All reported issues have been fixed, the API is simplified by v8.2.0 so everyone can
create and use any back-end storage for application's sessions persistence.

Mo, 07 August 2017 | v8.2.0

No Common-API Changes.

Good news for iris sessions back-end databases users.

Info for session database authors Session Database API Changed to:
type Database interface {
	Load(sid string) RemoteStore
	Sync(p SyncPayload)
}

// SyncPayload reports the state of the session inside a database sync action.
type SyncPayload struct {
	SessionID string

	Action Action
	// on insert it contains the new key and the value
	// on update it contains the existing key and the new value
	// on delete it contains the key (the value is nil)
	// on clear it contains nothing (empty key, value is nil)
	// on destroy it contains nothing (empty key, value is nil)
	Value memstore.Entry
	// Store contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Store RemoteStore
}


// RemoteStore is a helper which is a wrapper
// for the store, it can be used as the session "table" which will be
// saved to the session database.
type RemoteStore struct {
	// Values contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Values memstore.Store
	// on insert it contains the expiration datetime
	// on update it contains the new expiration datetime(if updated or the old one)
	// on delete it will be zero
	// on clear it will be zero
	// on destroy it will be zero
	Lifetime LifeTime
}

Read more at sessions/database.go, view how three built'n session databases are being implemented here.

All sessions databases are updated and they performant even faster than before.

  • NEW raw file-based session database implemented, example here
  • NEW boltdb-based session database implemented, example here (recommended as it's safer and faster)
  • redis sessiondb updated to the latest api

Under the cover, session database works entirely differently than before but nothing changed from the user's perspective, so upgrade with go get -u github.com/kataras/iris and sleep well.

Tu, 01 August 2017 | v8.1.3

  • Add Option function to the html view engine: #694
  • Fix sessions backend databases restore expiration: #692 by @corebreaker
  • Add PartyFunc, same as Party but receives a function with the sub router as its argument instead [GO1.9 Users-ONLY]

Mo, 31 July 2017 | v8.1.2

Add a ConfigureHost function as an alternative way to customize the hosts via host.Configurator.
The first way was to pass host.Configurator as optional arguments on iris.Runners built'n functions (iris#Server, iris#Listener, iris#Addr, iris#TLS, iris#AutoTLS), example of this can be found there.

Example Code:

package main

import (
	stdContext "context"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/host"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx context.Context) {
		ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
	})

    app.ConfigureHost(configureHost) // or pass "configureHost" as `app.Addr` argument, same result.

	app.Logger().Info("Wait 10 seconds and check your terminal again")
	// simulate a shutdown action here...
	go func() {
		<-time.After(10 * time.Second)
		timeout := 5 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		// close all hosts, this will notify the callback we had register
		// inside the `configureHost` func.
		app.Shutdown(ctx)
	}()

	// http://localhost:8080
	// wait 10 seconds and check your terminal.
	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func configureHost(su *host.Supervisor) {
	// here we have full access to the host that will be created
	// inside the `app.Run` or `app.NewHost` function .
	//
	// we're registering a shutdown "event" callback here:
	su.RegisterOnShutdown(func() {
		println("server is closed")
	})
	// su.RegisterOnError
	// su.RegisterOnServe
}

Su, 30 July 2017

Greetings my friends, nothing special today, no version number yet.

We just improve the, external, Iris Logging library and the Columns config field from middleware/logger defaults to false now. Upgrade with go get -u github.com/kataras/iris and have fun!

Sa, 29 July 2017 | v8.1.1

No breaking changes, just an addition to make your life easier.

This feature has been implemented after @corebreaker 's request, posted at: #688. He was also tried to fix that by a PR, we thanks him but the problem with that PR was the duplication and the separation of concepts, however we thanks him for pushing for a solution. The current feature's implementation gives a permant solution to host supervisor access issues.

Optional host configurators added to all common serve and listen functions.

Below you'll find how to gain access to the host, the second way is the new feature.

Hosts

Access to all hosts that serve your application can be provided by
the Application#Hosts field, after the Run method.

But the most common scenario is that you may need access to the host before the Run method,
there are two ways of gain access to the host supervisor, read below.

First way is to use the app.NewHost to create a new host
and use one of its Serve or Listen functions
to start the application via the iris#Raw Runner.
Note that this way needs an extra import of the net/http package.

Example Code:

h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){
    println("server was closed!")
})

app.Run(iris.Raw(h.ListenAndServe))

Second, and probably easier way is to use the host.Configurator.

Note that this method requires an extra import statement of
"github.com/kataras/iris/core/host" when using go < 1.9,
if you're targeting on go1.9 then you can use the iris#Supervisor
and omit the extra host import.

All common Runners we saw earlier (iris#Addr, iris#Listener, iris#Server, iris#TLS, iris#AutoTLS)
accept a variadic argument of host.Configurator, there are just func(*host.Supervisor).
Therefore the Application gives you the rights to modify the auto-created host supervisor through these.

Example Code:

package main

import (
    stdContext "context"
    "time"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
    "github.com/kataras/iris/core/host"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
        ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
    })

    app.Logger().Info("Wait 10 seconds and check your terminal again")
    // simulate a shutdown action here...
    go func() {
        <-time.After(10 * time.Second)
        timeout := 5 * time.Second
        ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
        defer cancel()
        // close all hosts, this will notify the callback we had register
        // inside the `configureHost` func.
        app.Shutdown(ctx)
    }()

    // start the server as usual, the only difference is that
    // we're adding a second (optional) function
    // to configure the just-created host supervisor.
    //
    // http://localhost:8080
    // wait 10 seconds and check your terminal.
    app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed))

}

func configureHost(su *host.Supervisor) {
    // here we have full access to the host that will be created
    // inside the `Run` function.
    //
    // we register a shutdown "event" callback
    su.RegisterOnShutdown(func() {
        println("server is closed")
    })
    // su.RegisterOnError
    // su.RegisterOnServe
}

Read more about listening and gracefully shutdown by navigating to: https://github.com/kataras/iris/tree/master/_examples/#http-listening

We, 26 July 2017 | v8.1.0

The app.Logger() *logrus.Logger was replaced with a custom implementation [golog], it's compatible with the logrus package and other open-source golang loggers as well, because of that: #680 (comment).

The API didn't change much except these:

  • the new implementation does not recognise Fatal and Panic because, actually, iris never panics
  • the old app.Logger().Out = io.Writer should be written as app.Logger().SetOutput(io.Writer)

The new implementation, golog is featured, three times faster than logrus
and it completes every common usage.

Integration

I understand that many of you may use logrus outside of Iris too. To integrate an external logrus logger just
Install it-- all print operations will be handled by the provided logrus instance.

import (
    "github.com/kataras/iris"
    "github.com/sirupsen/logrus"
)

package main(){
    app := iris.New()
    app.Logger().Install(logrus.StandardLogger()) // the package-level logrus instance
    // [...]
}

For more information about our new logger please navigate to: https://github.com/kataras/golog - contributions are welcomed as well!

Sa, 23 July 2017 | v8.0.7

Fix It's true that with UseGlobal the "/path1.txt" route call the middleware but cause the prepend, the order is inversed

Sa, 22 July 2017 | v8.0.5 & v8.0.6

No API Changes.

Performance

Add an experimental Configuration#EnableOptimizations option.

type Configuration {
    // [...]

    // EnableOptimization when this field is true
    // then the application tries to optimize for the best performance where is possible.
    //
    // Defaults to false.
    EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"`

    // [...]
}

Usage:

app.Run(iris.Addr(":8080"), iris.WithOptimizations)

Django view engine

@corebreaker pushed a PR to solve the Problem for {%extends%} in Django Engine with embedded files.

Logger

Remove the vendor/github.com/sirupsen/logrus folder, as a temporary solution for the #680 (comment).

Future versions

The logrus will be replaced with a custom implementation, because of that: #680 (comment).

As far as we know, @kataras is working on this new implementation, see here,
which will be compatible with the logrus package and other open-source golang loggers as well.

Mo, 17 July 2017 | v8.0.4

No API changes.

HTTP Errors

Fix a rare behavior: error handlers are not executed correctly
when a before-handler by-passes the order of execution, relative to the previous feature.

Request Logger

Add Configuration#MessageContextKey. Example can be found at _examples/http_request/request-logger/main.go.

Su, 16 July 2017 | v8.0.3

No API changes.

Relative issues:

HTTP Errors

Able to register a chain of Handlers (and middleware with ctx.Next() support like routes) for a specific error code, read more at issues/674. Usage example can be found at _examples/http_request/request-logger/main.go.

New function to register a Handler or a chain of Handlers for all official http error codes, by calling the new app.OnAnyErrorCode(func(ctx context.Context){}), read more at issues/675. Usage example can be found at _examples/http_request/request-logger/main.go.

Request Logger

Add Configuration#LogFunc and Configuration#Columns fields, read more at issues/676. Example can be found at _examples/http_request/request-logger/request-logger-file/main.go.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Sa, 15 July 2017 | v8.0.2

Okay my friends, this is a good time to upgrade, I did implement a feature that you were asking many times at the past.

Iris' router can now handle root-level wildcard paths app.Get("/{paramName:path}).

In case you're wondering: no it does not conflict with other static or dynamic routes, meaning that you can code something like this:

// it isn't conflicts with the rest of the static routes or dynamic routes with a path prefix.
app.Get("/{pathParamName:path}", myHandler) 

Or even like this:

package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
)

func main() {
	app := iris.New()

	// this works as expected now,
	// will handle all GET requests
	// except:
	// /                     -> because of app.Get("/", ...)
	// /other/anything/here  -> because of app.Get("/other/{paramother:path}", ...)
	// /other2/anything/here -> because of app.Get("/other2/{paramothersecond:path}", ...)
	// /other2/static        -> because of app.Get("/other2/static", ...)
	//
	// It isn't conflicts with the rest of the routes, without routing performance cost!
	//
	// i.e /something/here/that/cannot/be/found/by/other/registered/routes/order/not/matters
	app.Get("/{p:path}", h)

	// this will handle only GET /
	app.Get("/", staticPath)

	// this will handle all GET requests starting with "/other/"
	//
	// i.e /other/more/than/one/path/parts
	app.Get("/other/{paramother:path}", other)

	// this will handle all GET requests starting with "/other2/"
	// except /other2/static (because of the next static route)
	//
	// i.e /other2/more/than/one/path/parts
	app.Get("/other2/{paramothersecond:path}", other2)

	// this will handle only GET /other2/static
	app.Get("/other2/static", staticPath)

	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func h(ctx context.Context) {
	param := ctx.Params().Get("p")
	ctx.WriteString(param)
}

func other(ctx context.Context) {
	param := ctx.Params().Get("paramother")
	ctx.Writef("from other: %s", param)
}

func other2(ctx context.Context) {
	param := ctx.Params().Get("paramothersecond")
	ctx.Writef("from other2: %s", param)
}

func staticPath(ctx context.Context) {
	ctx.Writef("from the static path: %s", ctx.Path())
}

If you find any bugs with this change please send me a chat message in order to investigate it, I'm totally free at weekends.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Th, 13 July 2017 | v8.0.1

Nothing tremendous at this minor version.

We've just added a configuration field in order to ignore errors received by the Run function, see below.

Configuration#IgnoreServerErrors

type Configuration struct {
    // [...]

    // IgnoreServerErrors will cause to ignore the matched "errors"
    // from the main application's `Run` function.
    // This is a slice of string, not a slice of error
    // users can register these errors using yaml or toml configuration file
    // like the rest of the configuration fields.
    //
    // See `WithoutServerError(...)` function too.
    //
    // Defaults to an empty slice.
    IgnoreServerErrors []string `yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`

    // [...]
}

Configuration#WithoutServerError

// WithoutServerError will cause to ignore the matched "errors"
// from the main application's `Run` function.
//
// Usage:
// err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
//
// See `Configuration#IgnoreServerErrors []string` too.
WithoutServerError(errors ...error) Configurator

By default no error is being ignored, of course.

Example code:
_examples/http-listening/listen-addr/omit-server-errors

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
    	ctx.HTML("<h1>Hello World!/</h1>")
    })

    err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    if err != nil {
        // do something
    }
    // same as:
    // err := app.Run(iris.Addr(":8080"))
    // if err != nil && (err != iris.ErrServerClosed || err.Error() != iris.ErrServerClosed.Error()) {
    //     [...]
    // }
}

At first we didn't want to implement something like that because it's ridiculous easy to do it manually but a second thought came to us,
that many applications are based on configuration, therefore it would be nice to have something to ignore errors
by simply string values that can be passed to the application's configuration via toml or yaml files too.

This feature has been implemented after a request of ignoring the iris/http#ErrServerClosed from the Run function:
#668

Mo, 10 July 2017 | v8.0.0

📈 One and a half years with Iris and You...

Despite the deflamations, the clickbait articles, the removed posts of mine at reddit/r/golang, the unexpected and inadequate ban from the gophers slack room by @dlsniper alone the previous week without any reason or inform, Iris is still here and will be.

  • 7070 github stars
  • 749 github forks
  • 1m total views at its documentation
  • ~800$ at donations (there're a lot for a golang open-source project, thanks to you)
  • ~550 reported bugs fixed
  • ~30 community feature requests have been implemented

🔥 Reborn

As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore.

After a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community.

The leadership of this, open-source, repository was transferred to hiveminded, the author of iris-based get-ion/ion, he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s).

These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me!

📰 Changelog

app. = app := iris.New(); app.

ctx. = func(ctx context.Context) { ctx. }

Docker

Docker and kubernetes integration showcase, see the iris-contrib/cloud-native-go repository as an example.

Logger

  • Logger which was an io.Writer was replaced with the pluggable logrus.
    • which you still attach an io.Writer with app.Logger().Out = an io.Writer.
    • iris as always logs only critical errors, you can disable them with app.Logger().Level = iris.NoLog
    • the request logger outputs the incoming requests as INFO level.

Sessions

Remove ctx.Session() and app.AttachSessionManager, devs should import and use the sessions package as standalone, it's totally optional, devs can use any other session manager too. Examples here.

Websockets

The github.com/kataras/iris/websocket package does not handle the endpoint and client side automatically anymore. Example code:

func setupWebsocket(app *iris.Application) {
    // create our echo websocket server
    ws := websocket.New(websocket.Config{
    	ReadBufferSize:  1024,
    	WriteBufferSize: 1024,
    })
    ws.OnConnection(handleConnection)
    // serve the javascript built'n client-side library,
    // see weboskcets.html script tags, this path is used.
    app.Any("/iris-ws.js", func(ctx context.Context) {
    	ctx.Write(websocket.ClientSource)
    })

    // register the server on an endpoint.
    // see the inline javascript code in the websockets.html, this endpoint is used to connect to the server.
    app.Get("/echo", ws.Handler())
}

More examples here

View

Rename app.AttachView(...) to app.RegisterView(...).

Users can omit the import of github.com/kataras/iris/view and use the github.com/kataras/iris package to
refer to the view engines, i.e: app.RegisterView(iris.HTML("./templates", ".html")) is the same as import "github.com/kataras/iris/view" [...] app.RegisterView(view.HTML("./templates" ,".html")).

Examples here

Security

At previous versions, when you called ctx.Remoteaddr() Iris could parse and return the client's IP from the "X-Real-IP", "X-Forwarded-For" headers. This was a security leak as you can imagine, because the user can modify them. So we've disabled these headers by-default and add an option to add/remove request headers that are responsible to parse and return the client's real IP.

// WithRemoteAddrHeader enables or adds a new or existing request header name
// that can be used to validate the client's real IP.
//
// Existing values are:
// "X-Real-Ip":             false,
// "X-Forwarded-For":       false,
// "CF-Connecting-IP": false
//
// Look `context.RemoteAddr()` for more.
WithRemoteAddrHeader(headerName string) Configurator // enables a header.
WithoutRemoteAddrHeader(headerName string) Configurator // disables a header.

For example, if you want to enable the "CF-Connecting-IP" header (cloudflare)
you have to add the WithRemoteAddrHeader option to the app.Run function, at the end of your program.

app.Run(iris.Addr(":8080"), iris.WithRemoteAddrHeader("CF-Connecting-IP"))
// This header name will be checked when ctx.RemoteAddr() called and if exists
// it will return the client's IP, otherwise it will return the default *http.Request's `RemoteAddr` field.

Miscellaneous

Fix typescript tools.

_examples folder has been ordered by feature and usage:
- contains tests on some examples
- new examples added, one of them shows how the reuseport feature on UNIX and BSD systems can be used to listen for incoming connections, see here

Replace supervisor's tasks with events, like RegisterOnShutdown, RegisterOnError, RegisterOnServe and fix the (unharmful) race condition when output the banner to the console. Global notifier for interrupt signals which can be disabled via app.Run([...], iris.WithoutInterruptHandler), look graceful-shutdown example for more.

More handlers are ported to Iris (they can be used as they are without iris.FromStd), these handlers can be found at iris-contrib/middleware. Feel free to put your own there.

Middleware Description Example
jwt Middleware checks for a JWT on the Authorization header on incoming requests and decodes it. iris-contrib/middleware/jwt/_example
cors HTTP Access Control. iris-contrib/middleware/cors/_example
secure Middleware that implements a few quick security wins. iris-contrib/middleware/secure/_example
tollbooth Generic middleware to rate-limit HTTP requests. iris-contrib/middleware/tollbooth/_examples/limit-handler
cloudwatch AWS cloudwatch metrics middleware. iris-contrib/middleware/cloudwatch/_example
new relic Official New Relic Go Agent. iris-contrib/middleware/newrelic/_example
prometheus Easily create metrics endpoint for the prometheus instrumentation tool iris-contrib/middleware/prometheus/_example

v7.x is deprecated because it sold as it is and it is not part of the public, stable gopkg.in iris versions. Developers/users of this library should upgrade their apps to v8.x, the refactor process will cost nothing for most of you, as the most common API remains as it was. The changelog history from that are being presented below.

Th, 15 June 2017 | v7.2.0

About our new home page

https://iris-go.com

Thanks to Santosh Anand the https://iris-go.com has been upgraded and it's really awesome!

Santosh is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.

The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!

Cache

Declare the iris.Cache alias to the new, improved and most-suited for common usage, cache.Handler function.

iris.Cache be used as middleware in the chain now, example here. However you can still use the cache as a wrapper by importing the github.com/kataras/iris/cache package.

File server

  • Fix that.

  • app.StaticHandler(requestPath string, systemPath string, showList bool, gzip bool) -> app.StaticHandler(systemPath,showList bool, gzip bool)

  • New feature for Single Page Applications, app.SPA(assetHandler context.Handler) implemented.

  • New app.StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) added in order to be able to pass that on app.SPA(app.StaticEmbeddedHandler("./public", Asset, AssetNames)).

  • Fix app.StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string).

Examples:

app.StaticWeb doesn't works for root request path "/" anymore, use the new app.SPA instead.

WWW subdomain entry

  • Example added to copy all application's routes, including parties, to the www.mydomain.com

Wrapping the Router

  • Example added to show you how you can use the app.WrapRouter
    to implement a similar to app.SPA functionality, don't panic, it's easier than it sounds.

Testing

  • httptest.New(app *iris.Application, t *testing.T) -> httptest.New(t *testing.T, app *iris.Application).

  • New httptest.NewLocalListener() net.Listener added.

  • New httptest.NewLocalTLSListener(tcpListener net.Listener) net.Listener added.

Useful for testing tls-enabled servers:

Proxies are trying to understand local addresses in order to allow InsecureSkipVerify.

  • host.ProxyHandler(target *url.URL) *httputil.ReverseProxy.

  • host.NewProxy(hostAddr string, target *url.URL) *Supervisor.

    Tests here.

Tu, 13 June 2017 | v7.1.1

Fix that.

Mo, 12 June 2017 | v7.1.0

Fix that.

Su, 11 June 2017 | v7.0.5

Iris now supports static paths and dynamic paths for the same path prefix with zero performance cost:

app.Get("/profile/{id:int}", handler) and app.Get("/profile/create", createHandler) are not in conflict anymore.

The rest of the special Iris' routing features, including static & wildcard subdomains are still work like a charm.

This was one of the most popular community's feature requests. Click here to see a trivial example.

Sa, 10 June 2017 | v7.0.4

  • Simplify and add a test for the basicauth middleware, no need to be
    stored inside the Context anymore, developers can get the validated user(username and password) via context.Request().BasicAuth(). basicauth.Config.ContextKey was removed, just remove that field from your configuration, it's useless now.

Sa, 10 June 2017 | v7.0.3

  • New context.Session().PeekFlash("key") added, unlike GetFlash this will return the flash value but keep the message valid for the next requests too.
  • Complete the httptest example.
  • Fix the (marked as deprecated) ListenLETSENCRYPT function.
  • Upgrade the iris-contrib/middleware including JWT, CORS and Secure handlers.
  • Add OAuth2 example -- showcases the third-party package goth integration with Iris.

Community

Th, 08 June 2017 | v7.0.2

  • Able to set immutable data on sessions and context's storage. Aligned to fix an issue on slices and maps as reported here.

We, 07 June 2017 | v7.0.1

  • Proof of concept of an internal release generator, navigate here to read more.
  • Remove tray icon "feature", click here to learn why.

Sa, 03 June 2017

After 2+ months of hard work and collaborations, Iris version 7 was published earlier today.

If you're new to Iris you don't have to read all these, just navigate to the updated examples and you should be fine:)

Note that this section will not
cover the internal changes, the difference is so big that anybody can see them with a glimpse, even the code structure itself.

Changes from v6

The whole framework was re-written from zero but I tried to keep the most common public API that iris developers use.

Vendoring /w update

The previous vendor action for v6 was done by-hand, now I'm using the go dep tool, I had to do
some small steps:

  • remove files like testdata to reduce the folder size
  • rollback some of the "golang/x/net/ipv4" and "ipv6" source files because they are downloaded to their latest versions
    by go dep, but they had lines with the typealias feature, which is not ready by current golang version (it will be on August)
  • fix "cannot use internal package" at golang/x/net/ipv4 and ipv6 packages
    • rename the interal folder to was-internal, everywhere and fix its references.
  • fix "main redeclared in this block"
    • remove all examples folders.
  • remove main.go files on jsondiff lib, used by gavv/httpexpect, produces errors on test -v ./... while jd and jp folders are not used at all.

The go dep tool does what is says, as expected, don't be afraid of it now.
I am totally recommending this tool for package authors, even if it's in its alpha state.
I remember when Iris was in its alpha state and it had 4k stars on its first weeks/or month and that helped me a lot to fix reported bugs by users and make the framework even better, so give love to go dep from today!

General

  • Several enhancements for the typescript transpiler, view engine, websocket server and sessions manager
  • All Listen methods replaced with a single Run method, see here
  • Configuration, easier to modify the defaults, see here
  • HandlerFunc removed, just Handler of func(context.Context) where context.Context derives from import "github.com/kataras/iris/context" (NEW: this import path is optional, use iris.Context if you've installed Go 1.9)
    • Simplify API, i.e: instead of Handle,HandleFunc,Use,UseFunc,Done,DoneFunc,UseGlobal,UseGlobalFunc use Handle,Use,Done,UseGlobal.
  • Response time decreased even more (9-35%, depends on the application)
  • The Adaptors idea replaced with a more structural design pattern, but you have to apply these changes:
    • app.Adapt(view.HTML/Pug/Amber/Django/Handlebars...) -> app.AttachView(view.HTML/Pug/Amber/Django/Handlebars...)
    • app.Adapt(sessions.New(...)) -> app.AttachSessionManager(sessions.New(...))
    • app.Adapt(iris.LoggerPolicy(...)) -> app.AttachLogger(io.Writer)
    • app.Adapt(iris.RenderPolicy(...)) -> removed and replaced with the ability to replace the whole context with a custom one or override some methods of it, see below.

Routing

  • Remove of multiple routers, now we have the fresh Iris router which is based on top of the julien's httprouter.

    Update 11 June 2017: As of 7.0.5 this is changed, read here.

  • Subdomains routing algorithm has been improved.
  • Iris router is using a custom interpreter with parser and path evaluator to achieve the best expressiveness, with zero performance loss, you ever seen so far, i.e:
    • app.Get("/", "/users/{userid:int min(1)}", handler),
      • {username:string} or just {username}
      • {asset:path},
      • {firstname:alphabetical},
      • {requestfile:file} ,
      • {mylowercaseParam regexp([a-z]+)}.
      • The previous syntax of :param and *param still working as expected. Previous rules for paths confliction remain as they were.
        • Also, path parameter names should be only alphabetical now, numbers and symbols are not allowed (for your own good, I have seen a lot the last year...).

Click here for details.

It was my first attempt/experience on the interpreters field, so be good with it :)

Context

  • iris.Context pointer replaced with context.Context interface as we already mention
    • in order to be able to use a custom context and/or catch lifetime like BeginRequest and EndRequest from context itself, see below
  • context.JSON, context.JSONP, context.XML, context.Markdown, context.HTML work faster
  • context.Render("filename.ext", bindingViewData{}, options) -> context.View("filename.ext")
    • View renders only templates, it will not try to search if you have a restful renderer adapted, because, now, you can do it via method overriding using a custom Context.
    • Able to set context.ViewData and context.ViewLayout via middleware when executing a template.
  • context.SetStatusCode(statusCode) -> context.StatusCode(statusCode)
    • which is equivalent with the old EmitError too:
      • if status code >=400 given can automatically fire a custom http error handler if response wasn't written already.
    • context.StatusCode() -> context.GetStatusCode()
    • app.OnError -> app.OnErrorCode
    • Errors per party are removed by-default, you can just use one global error handler with logic like "if path starts with 'prefix' fire this error handler, else...".
  • Easy way to change Iris' default Context with a custom one, see here
  • context.ResponseWriter().SetBeforeFlush(...) works for Flush and HTTP/2 Push, respectfully
  • Several improvements under the Request transactions
  • Remember that you had to set a status code on each of the render-relative methods? Now it's not required, it just renders
    with the status code that user gave with context.StatusCode or with 200 OK, i.e:
    -context.JSON(iris.StatusOK, myJSON{}) -> context.JSON(myJSON{}).
    • Each one of the context's render methods has optional per-call settings,
    • the new API is even more easier to read, understand and use.

Server

  • Able to set custom underline *http.Server(s) with new Host (aka Server Supervisor) feature
    • Done and Err channels to catch shutdown or any errors on custom hosts,
    • Schedule custom tasks(with cancelation) when server is running, see here
  • Interrupt handler task for gracefully shutdown (when CTRL/CMD+C) are enabled by-default, you can disable its via configuration: app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler)

Future plans

  • Future Go1.9's ServeTLS is ready when 1.9 released
  • Future Go1.9's typealias feature is ready when 1.9 released, i.e context.Context -> iris.Context just one import path instead of todays' two.

v8.4.5

@kataras kataras released this Oct 6, 2017 · 276 commits to master since this release

FAQ

Looking for free support?

http://support.iris-go.com
https://kataras.rocket.chat/channel/iris

Fr, 06 October 2017 | v8.4.5

  • Badger team added support for transactions yesterday, therefore the badger session database is updated via 0b48927.
  • MVC: Support more than one path parameters with a single By, when the By keyword is the last word and the func's input arguments are more than one i.e GetBy(name string, age int), note that you can still use the older way of doing this; GetByBy(string, int). It's an enhancement of the #751 feature request.
  • MVC: Give controllers the ability to auto-initialize themselves by OnActivate func derives from the new ActivateListener interface, this can be used to perform any custom actions when the app registers the supported Controllers. See mvc/session_controller.go for a good use case.
  • errors.Reporter.AddErr returns true if the error is added to the stack, otherwise false.
  • @ZaniaDeveloper fixed #778 with PR: #779.
  • Add StatusSeeOther at mvc login example for Redirection, reported by @motecshine at #777.
  • Fix DisableVersionChecker configuration field is not being passed correctly when it was true via iris.Run(..., iris.WithConfiguration{DisableVersionChecker:true, ...}) call.

Su, 01 October 2017 | v8.4.4

  • Fix #762 reported by @xkylsoft
  • Fix #771 reported by @cdren
  • Improvements to the memstore's GetInt, GetInt64, GetFloat64, GetBool and remove the golang/net/context's interface completion from Context, read the changes for more
  • Add two examples for folder structuring as requested at #748
  • Add node.js express benchmarks similar to iris and netcore

We, 27 September 2017 | v8.4.3

Fr, 15 September 2017 | v8.4.2

MVC

Support more than one dynamic method function receivers.

package main

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Controller("/user", new(UserController))
    app.Run(iris.Addr("localhost:8080"))
}

type UserController struct { iris.Controller }

// Maps to GET /user
// Request example: http://localhost:8080/user
// as usual.
func (c *UserController) Get() {
    c.Text = "hello from /user"
}

// Maps to GET /user/{paramfirst:long}
// Request example: http://localhost:8080/user/42
// as usual.
func (c *UserController) GetBy(userID int64) {
    c.Ctx.Writef("hello user with id: %d", userID)
}

// NEW:
// Maps to GET /user/{paramfirst:long}/business/{paramsecond:long}
// Request example: http://localhost:8080/user/42/business/93
func (c *UserController) GetByBusinessBy(userID int64, businessID int64) {
    c.Ctx.Writef("fetch a business id: %d that user with id: %d owns, may make your db query faster",
    businessID, userID)
}

Th, 07 September 2017 | v8.4.1

Routing

Add a macro type for booleans: app.Get("/mypath/{paramName:boolean}", myHandler).

+------------------------+
| {param:boolean}        |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"

Add context.Params().GetBool(paramName string) (bool, error) respectfully.

app := iris.New()
app.Get("/mypath/{has:boolean}", func(ctx iris.Context) { // <--
    // boolean first return value
    // error as second return value
    //
    // error will be always nil here because
    // we use the {has:boolean} so router
    // makes sure that the parameter is a boolean
    // otherwise it will return a 404 not found http error code
    // skipping the call of this handler.
    has, _ := ctx.Params().GetBool("has") // <--
    if has {
        ctx.HTML("<strong>it's true</strong>")
    }else {
        ctx.HTML("<strong>it's false</string>")
    }
})
// [...]

MVC

Support for boolean method receivers, i.e GetBy(bool), PostBy(bool)....

app := iris.New()

app.Controller("/equality", new(Controller))
type Controller struct {
    iris.Controller
}

// handles the "/equality" path.
func (c *Controller) Get() {

}

// registers and handles the path: "/equality/{param:boolean}".
func (c *Controller) GetBy(is bool) { // <--
    // [...]
}

Supported types for method functions receivers are: int, int64, bool and string.

Su, 27 August 2017 | v8.4.0

Miscellaneous

Router

Add a new macro type for path parameters, long, it's the go type int64.

app.Get("/user/{id:long}", func(ctx context.Context) {
	userID, _ := ctx.Params().GetInt64("id")
})

MVC

The ability to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that after a go get -u github.com/kataras/iris you will be able to use things like these:

If app.Controller("/user", new(user.Controller))

  • func(*Controller) Get() - GET:/user , as usual.
  • func(*Controller) Post() - POST:/user, as usual.
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

If app.Controller("/profile", new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

If app.Controller("/assets", new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

Example can be found at: _examples/mvc/login/user/controller.go.

Pretty awesome, right?

We, 23 August 2017 | v8.3.4

Give read access to the current request context's route, a feature that many of you asked a lot.

func(ctx context.Context) {
	_ = ctx.GetCurrentRoute().Name()
	//					.Method() returns string, same as ctx.Method().
	//					.Subdomain() returns string, the registered subdomain.
	//					.Path() returns string, the registered path.
	//					.IsOnline() returns boolean.
}
type MyController struct {
	mvc.Controller
}

func (c *MyController) Get(){
	_ = c.Route().Name() // same as `c.Ctx.GetCurrentRoute().Name()`.
	// [...]
}

Updated: 24 August 2017

This evening, on the next version 8.3.5:

Able to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that in the future you will be able to use something like these:

If app.Controller("/user", new(user.Controller))

  • func(c *Controller) Get() - GET:/user , as usual.
  • func(c *Controller) Post() - POST:/user, as usual.
  • func(c *Controller) GetLogin() - GET:/user/login
  • func(c *Controller) PostLogin() - POST:/user/login
  • func(c *Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(c *Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(c *Controller) GetBy() - GET:/user/{param}
  • func(c *Controller) GetByName(name string) - GET:/user/{name}
  • func(c *Controller) PostByName(name string) - POST:/user/{name}
  • func(c *Controller) GetByID(id int64 || int) - GET:/user/{id:int}
  • func(c *Controller) PostByID(id int64 || int) - POST:/user/{id:int}

Watch and stay tuned my friends.

We, 23 August 2017 | v8.3.3

Better debug messages when using MVC.

Add support for recursively binding and custom controllers embedded to other custom controller, that's the new feature. That simply means that Iris users are able to use "shared" controllers everywhere; when binding, using models, get/set persistence data, adding middleware, intercept request flow.

This will help web authors to split the logic at different controllers. Those controllers can be also used as "standalone" to serve a page somewhere else in the application as well.

My personal advice to you is to always organize and split your code nicely and wisely in order to avoid using such as an advanced MVC feature, at least any time soon.

I'm aware that this is not always an easy task to do, therefore is here if you ever need it :)

A ridiculous simple example of this feature can be found at the mvc/controller_test.go file.

Tu, 22 August 2017 | v8.3.2

MVC

When one or more values of handler type (func(ctx context.Context)) are passed
right to the controller initialization then they will be recognised and act as middleware(s)
that ran even before the controller activation, there is no reason to load
the whole controller if the main handler or its BeginRequest are not "allowed" to be executed.

Example Code

func checkLogin(ctx context.Context) {
	if !myCustomAuthMethodPassed {
		// [set a status or redirect, you know what to do]
		ctx.StatusCode(iris.StatusForbidden)
		return
	}

	// [continue to the next handler, at this example is our controller itself]
	ctx.Next()
}

// [...]
app.Controller(new(ProfileController), checkLogin)
// [...]

Usage of these kind of MVC features could be found at the mvc/controller_test.go file.

Other minor enhancements

  • fix issue #726*
  • fix redis sessiondb expiration*
  • update recursively when new version is available*
  • some minor session enhancements*

Sa, 19 August 2017 | v8.3.1

First of all I want to thank you for the 100% green feedback you gratefully sent me you about
my latest article Go vs .NET Core in terms of HTTP performance, published at medium's hackernoon.com and dev.to. I really appreciate it💓

No API Changes.

However two more methods added to the Controller.

  • RelPath() string, returns the relative path based on the controller's name and the request path.
  • RelTmpl() string, returns the relative template directory based on the controller's name.

These are useful when dealing with big controllers, they help you to keep align with any
future changes inside your application.

Let's refactor our ProfileController enhancemed by these two new functions.

func (pc *ProfileController) tmpl(relativeTmplPath string) {
	// the relative template files directory of this controller.
	views := pc.RelTmpl()
	pc.Tmpl = views + relativeTmplPath
}

func (pc *ProfileController) match(relativeRequestPath string) bool {
	// the relative request path of this controller.
	path := pc.RelPath()
	return path == relativeRequestPath
}

func (pc *ProfileController) Get() {
	// requested: "/profile"
	// so relative path is "/" because of the ProfileController.
	if pc.match("/") {

		// views/profile/index.html
		pc.tmpl("index.html")
		return
	}

	// requested: "/profile/browse"
	// so relative path is "/browse".
	if pc.match("/browse") {
		pc.Path = "/profile"
		return
	}

	// requested: "/profile/me"
	// so the relative path is "/me"
	if pc.match("/me") {
		
		// views/profile/me.html
		pc.tmpl("me.html")
		return
	}

	// requested: "/profile/$ID"
	// so the relative path is "/$ID"
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound

		// views/profile/notfound.html
		pc.tmpl("notfound.html")
		pc.Data["ID"] = id
		return
	}

	// views/profile/profile.html
	pc.tmpl("profile.html")
	pc.User = user
}

Want to learn more about these functions? Go to the mvc/controller_test.go file and scroll to the bottom!

Fr, 18 August 2017 | v8.3.0

Good news for devs that are used to write their web apps using the MVC architecture pattern.

Implement a whole new mvc package with additional support for models and easy binding.

@kataras started to develop that feature by version 8.2.5, back then it didn't seem
to be a large feature and maybe a game-changer, so it lived inside the kataras/iris/core/router/controller.go file.
However with this version, so many things are implemented for the MVC and we needed a new whole package,
this new package is the kataras/iris/mvc, but if you used go 1.9 to build then you don't have to do any refactor, you could use the iris.Controller type alias.

People who used the mvc from its baby steps(v8.2.5) the only syntactic change you'll have to do is to rename the router.Controller to mvc.Controller:

Before:

import "github.com/kataras/iris/core/router"
type MyController struct {
    router.Controller
}

Now:

import "github.com/kataras/iris/mvc"
type MyController struct {
    mvc.Controller
    // if you build with go1.9 you can omit the import of mvc package
    // and just use `iris.Controller` instead.
}

MVC (Model View Controller)

From version 8.3 and after Iris has first-class support for the MVC pattern, you'll not find
these stuff anywhere else in the Go world.

Example Code

package main

import (
	"sync"

	"github.com/kataras/iris"
	"github.com/kataras/iris/mvc"
)

func main() {
	app := iris.New()
	app.RegisterView(iris.HTML("./views", ".html"))

	// when we have a path separated by spaces
	// then the Controller is registered to all of them one by one.
	//
	// myDB is binded to the controller's `*DB` field: use only structs and pointers.
	app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
		new(ProfileController), myDB) // IMPORTANT

	app.Run(iris.Addr(":8080"))
}

// UserModel our example model which will render on the template.
type UserModel struct {
	ID       int64
	Username string
}

// DB is our example database.
type DB struct {
	usersTable map[int64]UserModel
	mu         sync.RWMutex
}

// GetUserByID imaginary database lookup based on user id.
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
	db.mu.RLock()
	u, found = db.usersTable[id]
	db.mu.RUnlock()
	return
}

var myDB = &DB{
	usersTable: map[int64]UserModel{
		1:  {1, "kataras"},
		2:  {2, "makis"},
		42: {42, "jdoe"},
	},
}

// ProfileController our example user controller which controls
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
type ProfileController struct {
	mvc.Controller // IMPORTANT

	User UserModel `iris:"model"`
	// we will bind it but you can also tag it with`iris:"persistence"`
	// and init the controller with manual &PorifleController{DB: myDB}.
	DB *DB
}

// Get method handles all "GET" HTTP Method requests of the controller's paths.
func (pc *ProfileController) Get() { // IMPORTANT
	path := pc.Path

	// requested: /profile path
	if path == "/profile" {
		pc.Tmpl = "profile/index.html"
		return
	}
	// requested: /profile/browse
	// this exists only to proof the concept of changing the path:
	// it will result to a redirection.
	if path == "/profile/browse" {
		pc.Path = "/profile"
		return
	}

	// requested: /profile/me path
	if path == "/profile/me" {
		pc.Tmpl = "profile/me.html"
		return
	}

	// requested: /profile/$ID
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound
		pc.Tmpl = "profile/notfound.html"
		pc.Data["ID"] = id
		return
	}

	pc.Tmpl = "profile/profile.html"
	pc.User = user
}


/*
func (pc *ProfileController) Post() {}
func (pc *ProfileController) Put() {}
func (pc *ProfileController) Delete() {}
func (pc *ProfileController) Connect() {}
func (pc *ProfileController) Head() {}
func (pc *ProfileController) Patch() {}
func (pc *ProfileController) Options() {}
func (pc *ProfileController) Trace() {}
*/

/*
func (pc *ProfileController) All() {}
//        OR
func (pc *ProfileController) Any() {}
*/

Iris web framework supports Request data, Models, Persistence Data and Binding
with the fastest possible execution.

Characteristics

All HTTP Methods are supported, for example if want to serve GET
then the controller should have a function named Get(),
you can define more than one method function to serve in the same Controller struct.

Persistence data inside your Controller struct (share data between requests)
via iris:"persistence" tag right to the field or Bind using app.Controller("/" , new(myController), theBindValue).

Models inside your Controller struct (set-ed at the Method function and rendered by the View)
via iris:"model" tag right to the field, i.e User UserModel `iris:"model" name:"user"` view will recognise it as {{.user}}.
If name tag is missing then it takes the field's name, in this case the "User".

Access to the request path and its parameters via the Path and Params fields.

Access to the template file that should be rendered via the Tmpl field.

Access to the template data that should be rendered inside
the template file via Data field.

Access to the template layout via the Layout field.

Access to the low-level context.Context via the Ctx field.

Get the relative request path by using the controller's name via RelPath().

Get the relative template path directory by using the controller's name via RelTmpl().

Flow as you used to, Controllers can be registered to any Party,
including Subdomains, the Party's begin and done handlers work as expected.

Optional BeginRequest(ctx) function to perform any initialization before the method execution,
useful to call middlewares or when many methods use the same collection of data.

Optional EndRequest(ctx) function to perform any finalization after any method executed.

Inheritance, recursively, see for example our mvc.SessionController, it has the mvc.Controller as an embedded field
and it adds its logic to its BeginRequest, here.

Read access to the current route via the Route field.

Using Iris MVC for code reuse

By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.

If you're new to back-end web development read about the MVC architectural pattern first, a good start is that wikipedia article.

Follow the examples below,

Bugs

Fix #723 reported by @speedwheel.

Mo, 14 August 2017 | v8.2.6

Able to call done/end handlers inside a Controller, via optional EndRequest(ctx context.Context) function inside the controller struct.

// it's called after t.Get()/Post()/Put()/Delete()/Connect()/Head()/Patch()/Options()/Trace().
func (t *testControllerEndRequestFunc) EndRequest(ctx context.Context) {
    // 2.
    // [your code goes here...]
}

// will handle "GET" request HTTP method only.
func (t *testControllerEndRequestFunc) Get() {
    // 1.
    // [your code goes here...]
}

Look at the v8.2.5 changelog to learn more about the new Iris Controllers feature.

Su, 13 August 2017 | v8.2.5

Good news for devs that are used to write their web apps using the MVC-style app architecture.

Yesterday I wrote a tutorial on how you can transform your raw Handlers to Controllers using the existing tools only (Iris is the most modular web framework out there, we all have no doubt about this).

Today, I did implement the Controller idea as built'n feature inside Iris.
Our Controller supports many things among them are:

  • all HTTP Methods are supported, for example if want to serve GET then the controller should have a function named Get(), you can define more than one method function to serve in the same Controller struct
  • persistence data inside your Controller struct (share data between requests) via iris:"persistence" tag right to the field
  • optional BeginRequest(ctx) function to perform any initialization before the methods, useful to call middlewares or when many methods use the same collection of data
  • optional EndRequest(ctx) function to perform any finalization after the methods executed
  • access to the request path parameters via the Params field
  • access to the template file that should be rendered via the Tmpl field
  • access to the template data that should be rendered inside the template file via Data field
  • access to the template layout via the Layout field
  • access to the low-level context.Context via the Ctx field
  • flow as you used to, Controllers can be registered to any Party, including Subdomains, the Party's begin and done handlers work as expected.

It's very easy to get started, the only function you need to call instead of app.Get/Post/Put/Delete/Connect/Head/Patch/Options/Trace is the app.Controller.

Example Code:

// file: main.go

package main

import (
    "github.com/kataras/iris"

    "controllers"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    app.Controller("/", new(controllers.Index))

    // http://localhost:8080/
    app.Run(iris.Addr(":8080"))
}
// file: controllers/index.go

package controllers

import (
    "github.com/kataras/iris/core/router"
)

// Index is our index example controller.
type Index struct {
    mvc.Controller
    // if you're using go1.9: 
    // you can omit the /core/router import statement
    // and just use the `iris.Controller` instead.
}

// will handle GET method on http://localhost:8080/
func (c *Index) Get() {
    c.Tmpl = "index.html"
    c.Data["title"] = "Index page"
    c.Data["message"] = "Hello world!"
}

// will handle POST method on http://localhost:8080/
func (c *Index) Post() {}

Tip: declare a func(c *Index) All() {} or Any() to register all HTTP Methods.

A full example can be found at the _examples/mvc folder.

Sa, 12 August 2017 | v8.2.4

No API Changes.

Fix #717, users are welcomed to follow the thread for any questions or reports about Gzip and Static Files Handlers only.

Th, 10 August 2017 | v8.2.3

No API Changes.

Fix #714

Continue to v8.2.2 for more...

Th, 10 August 2017 | v8.2.2

No API Changes.

  • Implement Google reCAPTCHA middleware, example here
  • Fix kataras/golog prints with colors on windows server 2012 while it shouldn't because its command line tool does not support 256bit colors
  • Improve the updater by a custom self-updated back-end version checker, can be disabled by:
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)

Or

app.Configure(iris.WithoutVersionChecker)

Or

app.Configure(iris.WithConfiguration(iris.Configuration{DisableVersionChecker:true}))

Tu, 08 August 2017 | v8.2.1

No API Changes. Great news for the unique iris sessions library, once again.

NEW: LevelDB-based session database implemented, example here.

Redis-based sessiondb has no longer the MaxAgeSeconds config field,
this is passed automatically by the session manager, now.

All sessions databases have an Async(bool) function, if turned on
then all synchronization between the memory store and the back-end database will happen
inside different go routines. By-default async is false but it's recommended to turn it on, it will make sessions to be stored faster, at most.

All reported issues have been fixed, the API is simplified by v8.2.0 so everyone can
create and use any back-end storage for application's sessions persistence.

Mo, 07 August 2017 | v8.2.0

No Common-API Changes.

Good news for iris sessions back-end databases users.

Info for session database authors Session Database API Changed to:
type Database interface {
	Load(sid string) RemoteStore
	Sync(p SyncPayload)
}

// SyncPayload reports the state of the session inside a database sync action.
type SyncPayload struct {
	SessionID string

	Action Action
	// on insert it contains the new key and the value
	// on update it contains the existing key and the new value
	// on delete it contains the key (the value is nil)
	// on clear it contains nothing (empty key, value is nil)
	// on destroy it contains nothing (empty key, value is nil)
	Value memstore.Entry
	// Store contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Store RemoteStore
}


// RemoteStore is a helper which is a wrapper
// for the store, it can be used as the session "table" which will be
// saved to the session database.
type RemoteStore struct {
	// Values contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Values memstore.Store
	// on insert it contains the expiration datetime
	// on update it contains the new expiration datetime(if updated or the old one)
	// on delete it will be zero
	// on clear it will be zero
	// on destroy it will be zero
	Lifetime LifeTime
}

Read more at sessions/database.go, view how three built'n session databases are being implemented here.

All sessions databases are updated and they performant even faster than before.

  • NEW raw file-based session database implemented, example here
  • NEW boltdb-based session database implemented, example here (recommended as it's safer and faster)
  • redis sessiondb updated to the latest api

Under the cover, session database works entirely differently than before but nothing changed from the user's perspective, so upgrade with go get -u github.com/kataras/iris and sleep well.

Tu, 01 August 2017 | v8.1.3

  • Add Option function to the html view engine: #694
  • Fix sessions backend databases restore expiration: #692 by @corebreaker
  • Add PartyFunc, same as Party but receives a function with the sub router as its argument instead [GO1.9 Users-ONLY]

Mo, 31 July 2017 | v8.1.2

Add a ConfigureHost function as an alternative way to customize the hosts via host.Configurator.
The first way was to pass host.Configurator as optional arguments on iris.Runners built'n functions (iris#Server, iris#Listener, iris#Addr, iris#TLS, iris#AutoTLS), example of this can be found there.

Example Code:

package main

import (
	stdContext "context"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/host"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx context.Context) {
		ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
	})

    app.ConfigureHost(configureHost) // or pass "configureHost" as `app.Addr` argument, same result.

	app.Logger().Info("Wait 10 seconds and check your terminal again")
	// simulate a shutdown action here...
	go func() {
		<-time.After(10 * time.Second)
		timeout := 5 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		// close all hosts, this will notify the callback we had register
		// inside the `configureHost` func.
		app.Shutdown(ctx)
	}()

	// http://localhost:8080
	// wait 10 seconds and check your terminal.
	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func configureHost(su *host.Supervisor) {
	// here we have full access to the host that will be created
	// inside the `app.Run` or `app.NewHost` function .
	//
	// we're registering a shutdown "event" callback here:
	su.RegisterOnShutdown(func() {
		println("server is closed")
	})
	// su.RegisterOnError
	// su.RegisterOnServe
}

Su, 30 July 2017

Greetings my friends, nothing special today, no version number yet.

We just improve the, external, Iris Logging library and the Columns config field from middleware/logger defaults to false now. Upgrade with go get -u github.com/kataras/iris and have fun!

Sa, 29 July 2017 | v8.1.1

No breaking changes, just an addition to make your life easier.

This feature has been implemented after @corebreaker 's request, posted at: #688. He was also tried to fix that by a PR, we thanks him but the problem with that PR was the duplication and the separation of concepts, however we thanks him for pushing for a solution. The current feature's implementation gives a permant solution to host supervisor access issues.

Optional host configurators added to all common serve and listen functions.

Below you'll find how to gain access to the host, the second way is the new feature.

Hosts

Access to all hosts that serve your application can be provided by
the Application#Hosts field, after the Run method.

But the most common scenario is that you may need access to the host before the Run method,
there are two ways of gain access to the host supervisor, read below.

First way is to use the app.NewHost to create a new host
and use one of its Serve or Listen functions
to start the application via the iris#Raw Runner.
Note that this way needs an extra import of the net/http package.

Example Code:

h := app.NewHost(&http.Server{Addr:":8080"})
h.RegisterOnShutdown(func(){
    println("server was closed!")
})

app.Run(iris.Raw(h.ListenAndServe))

Second, and probably easier way is to use the host.Configurator.

Note that this method requires an extra import statement of
"github.com/kataras/iris/core/host" when using go < 1.9,
if you're targeting on go1.9 then you can use the iris#Supervisor
and omit the extra host import.

All common Runners we saw earlier (iris#Addr, iris#Listener, iris#Server, iris#TLS, iris#AutoTLS)
accept a variadic argument of host.Configurator, there are just func(*host.Supervisor).
Therefore the Application gives you the rights to modify the auto-created host supervisor through these.

Example Code:

package main

import (
    stdContext "context"
    "time"

    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
    "github.com/kataras/iris/core/host"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
        ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
    })

    app.Logger().Info("Wait 10 seconds and check your terminal again")
    // simulate a shutdown action here...
    go func() {
        <-time.After(10 * time.Second)
        timeout := 5 * time.Second
        ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
        defer cancel()
        // close all hosts, this will notify the callback we had register
        // inside the `configureHost` func.
        app.Shutdown(ctx)
    }()

    // start the server as usual, the only difference is that
    // we're adding a second (optional) function
    // to configure the just-created host supervisor.
    //
    // http://localhost:8080
    // wait 10 seconds and check your terminal.
    app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed))

}

func configureHost(su *host.Supervisor) {
    // here we have full access to the host that will be created
    // inside the `Run` function.
    //
    // we register a shutdown "event" callback
    su.RegisterOnShutdown(func() {
        println("server is closed")
    })
    // su.RegisterOnError
    // su.RegisterOnServe
}

Read more about listening and gracefully shutdown by navigating to: https://github.com/kataras/iris/tree/master/_examples/#http-listening

We, 26 July 2017 | v8.1.0

The app.Logger() *logrus.Logger was replaced with a custom implementation [golog], it's compatible with the logrus package and other open-source golang loggers as well, because of that: #680 (comment).

The API didn't change much except these:

  • the new implementation does not recognise Fatal and Panic because, actually, iris never panics
  • the old app.Logger().Out = io.Writer should be written as app.Logger().SetOutput(io.Writer)

The new implementation, golog is featured, three times faster than logrus
and it completes every common usage.

Integration

I understand that many of you may use logrus outside of Iris too. To integrate an external logrus logger just
Install it-- all print operations will be handled by the provided logrus instance.

import (
    "github.com/kataras/iris"
    "github.com/sirupsen/logrus"
)

package main(){
    app := iris.New()
    app.Logger().Install(logrus.StandardLogger()) // the package-level logrus instance
    // [...]
}

For more information about our new logger please navigate to: https://github.com/kataras/golog - contributions are welcomed as well!

Sa, 23 July 2017 | v8.0.7

Fix It's true that with UseGlobal the "/path1.txt" route call the middleware but cause the prepend, the order is inversed

Sa, 22 July 2017 | v8.0.5 & v8.0.6

No API Changes.

Performance

Add an experimental Configuration#EnableOptimizations option.

type Configuration {
    // [...]

    // EnableOptimization when this field is true
    // then the application tries to optimize for the best performance where is possible.
    //
    // Defaults to false.
    EnableOptimizations bool `yaml:"EnableOptimizations" toml:"EnableOptimizations"`

    // [...]
}

Usage:

app.Run(iris.Addr(":8080"), iris.WithOptimizations)

Django view engine

@corebreaker pushed a PR to solve the Problem for {%extends%} in Django Engine with embedded files.

Logger

Remove the vendor/github.com/sirupsen/logrus folder, as a temporary solution for the #680 (comment).

Future versions

The logrus will be replaced with a custom implementation, because of that: #680 (comment).

As far as we know, @kataras is working on this new implementation, see here,
which will be compatible with the logrus package and other open-source golang loggers as well.

Mo, 17 July 2017 | v8.0.4

No API changes.

HTTP Errors

Fix a rare behavior: error handlers are not executed correctly
when a before-handler by-passes the order of execution, relative to the previous feature.

Request Logger

Add Configuration#MessageContextKey. Example can be found at _examples/http_request/request-logger/main.go.

Su, 16 July 2017 | v8.0.3

No API changes.

Relative issues:

HTTP Errors

Able to register a chain of Handlers (and middleware with ctx.Next() support like routes) for a specific error code, read more at issues/674. Usage example can be found at _examples/http_request/request-logger/main.go.

New function to register a Handler or a chain of Handlers for all official http error codes, by calling the new app.OnAnyErrorCode(func(ctx context.Context){}), read more at issues/675. Usage example can be found at _examples/http_request/request-logger/main.go.

Request Logger

Add Configuration#LogFunc and Configuration#Columns fields, read more at issues/676. Example can be found at _examples/http_request/request-logger/request-logger-file/main.go.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Sa, 15 July 2017 | v8.0.2

Okay my friends, this is a good time to upgrade, I did implement a feature that you were asking many times at the past.

Iris' router can now handle root-level wildcard paths app.Get("/{paramName:path}).

In case you're wondering: no it does not conflict with other static or dynamic routes, meaning that you can code something like this:

// it isn't conflicts with the rest of the static routes or dynamic routes with a path prefix.
app.Get("/{pathParamName:path}", myHandler) 

Or even like this:

package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
)

func main() {
	app := iris.New()

	// this works as expected now,
	// will handle all GET requests
	// except:
	// /                     -> because of app.Get("/", ...)
	// /other/anything/here  -> because of app.Get("/other/{paramother:path}", ...)
	// /other2/anything/here -> because of app.Get("/other2/{paramothersecond:path}", ...)
	// /other2/static        -> because of app.Get("/other2/static", ...)
	//
	// It isn't conflicts with the rest of the routes, without routing performance cost!
	//
	// i.e /something/here/that/cannot/be/found/by/other/registered/routes/order/not/matters
	app.Get("/{p:path}", h)

	// this will handle only GET /
	app.Get("/", staticPath)

	// this will handle all GET requests starting with "/other/"
	//
	// i.e /other/more/than/one/path/parts
	app.Get("/other/{paramother:path}", other)

	// this will handle all GET requests starting with "/other2/"
	// except /other2/static (because of the next static route)
	//
	// i.e /other2/more/than/one/path/parts
	app.Get("/other2/{paramothersecond:path}", other2)

	// this will handle only GET /other2/static
	app.Get("/other2/static", staticPath)

	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func h(ctx context.Context) {
	param := ctx.Params().Get("p")
	ctx.WriteString(param)
}

func other(ctx context.Context) {
	param := ctx.Params().Get("paramother")
	ctx.Writef("from other: %s", param)
}

func other2(ctx context.Context) {
	param := ctx.Params().Get("paramothersecond")
	ctx.Writef("from other2: %s", param)
}

func staticPath(ctx context.Context) {
	ctx.Writef("from the static path: %s", ctx.Path())
}

If you find any bugs with this change please send me a chat message in order to investigate it, I'm totally free at weekends.

Have fun and don't forget to star the github repository, it gives me power to continue publishing my work!

Th, 13 July 2017 | v8.0.1

Nothing tremendous at this minor version.

We've just added a configuration field in order to ignore errors received by the Run function, see below.

Configuration#IgnoreServerErrors

type Configuration struct {
    // [...]

    // IgnoreServerErrors will cause to ignore the matched "errors"
    // from the main application's `Run` function.
    // This is a slice of string, not a slice of error
    // users can register these errors using yaml or toml configuration file
    // like the rest of the configuration fields.
    //
    // See `WithoutServerError(...)` function too.
    //
    // Defaults to an empty slice.
    IgnoreServerErrors []string `yaml:"IgnoreServerErrors" toml:"IgnoreServerErrors"`

    // [...]
}

Configuration#WithoutServerError

// WithoutServerError will cause to ignore the matched "errors"
// from the main application's `Run` function.
//
// Usage:
// err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
//
// See `Configuration#IgnoreServerErrors []string` too.
WithoutServerError(errors ...error) Configurator

By default no error is being ignored, of course.

Example code:
_examples/http-listening/listen-addr/omit-server-errors

package main

import (
    "github.com/kataras/iris"
    "github.com/kataras/iris/context"
)

func main() {
    app := iris.New()

    app.Get("/", func(ctx context.Context) {
    	ctx.HTML("<h1>Hello World!/</h1>")
    })

    err := app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    if err != nil {
        // do something
    }
    // same as:
    // err := app.Run(iris.Addr(":8080"))
    // if err != nil && (err != iris.ErrServerClosed || err.Error() != iris.ErrServerClosed.Error()) {
    //     [...]
    // }
}

At first we didn't want to implement something like that because it's ridiculous easy to do it manually but a second thought came to us,
that many applications are based on configuration, therefore it would be nice to have something to ignore errors
by simply string values that can be passed to the application's configuration via toml or yaml files too.

This feature has been implemented after a request of ignoring the iris/http#ErrServerClosed from the Run function:
#668

Mo, 10 July 2017 | v8.0.0

📈 One and a half years with Iris and You...

Despite the deflamations, the clickbait articles, the removed posts of mine at reddit/r/golang, the unexpected and inadequate ban from the gophers slack room by @dlsniper alone the previous week without any reason or inform, Iris is still here and will be.

  • 7070 github stars
  • 749 github forks
  • 1m total views at its documentation
  • ~800$ at donations (there're a lot for a golang open-source project, thanks to you)
  • ~550 reported bugs fixed
  • ~30 community feature requests have been implemented

🔥 Reborn

As you may have heard I have huge responsibilities on my new position at Dubai nowadays, therefore I don't have the needed time to work on this project anymore.

After a month of negotiations and searching I succeed to find a decent software engineer to continue my work on the open source community.

The leadership of this, open-source, repository was transferred to hiveminded, the author of iris-based get-ion/ion, he actually did an excellent job on the framework, he kept the code as minimal as possible and at the same time added more features, examples and middleware(s).

These types of projects need heart and sacrifices to continue offer the best developer experience like a paid software, please do support him as you did with me!

📰 Changelog

app. = app := iris.New(); app.

ctx. = func(ctx context.Context) { ctx. }

Docker

Docker and kubernetes integration showcase, see the iris-contrib/cloud-native-go repository as an example.

Logger

  • Logger which was an io.Writer was replaced with the pluggable logrus.
    • which you still attach an io.Writer with app.Logger().Out = an io.Writer.
    • iris as always logs only critical errors, you can disable them with app.Logger().Level = iris.NoLog
    • the request logger outputs the incoming requests as INFO level.

Sessions

Remove ctx.Session() and app.AttachSessionManager, devs should import and use the sessions package as standalone, it's totally optional, devs can use any other session manager too. Examples here.

Websockets

The github.com/kataras/iris/websocket package does not handle the endpoint and client side automatically anymore. Example code:

func setupWebsocket(app *iris.Application) {
    // create our echo websocket server
    ws := websocket.New(websocket.Config{
    	ReadBufferSize:  1024,
    	WriteBufferSize: 1024,
    })
    ws.OnConnection(handleConnection)
    // serve the javascript built'n client-side library,
    // see weboskcets.html script tags, this path is used.
    app.Any("/iris-ws.js", func(ctx context.Context) {
    	ctx.Write(websocket.ClientSource)
    })

    // register the server on an endpoint.
    // see the inline javascript code in the websockets.html, this endpoint is used to connect to the server.
    app.Get("/echo", ws.Handler())
}

More examples here

View

Rename app.AttachView(...) to app.RegisterView(...).

Users can omit the import of github.com/kataras/iris/view and use the github.com/kataras/iris package to
refer to the view engines, i.e: app.RegisterView(iris.HTML("./templates", ".html")) is the same as import "github.com/kataras/iris/view" [...] app.RegisterView(view.HTML("./templates" ,".html")).

Examples here

Security

At previous versions, when you called ctx.Remoteaddr() Iris could parse and return the client's IP from the "X-Real-IP", "X-Forwarded-For" headers. This was a security leak as you can imagine, because the user can modify them. So we've disabled these headers by-default and add an option to add/remove request headers that are responsible to parse and return the client's real IP.

// WithRemoteAddrHeader enables or adds a new or existing request header name
// that can be used to validate the client's real IP.
//
// Existing values are:
// "X-Real-Ip":             false,
// "X-Forwarded-For":       false,
// "CF-Connecting-IP": false
//
// Look `context.RemoteAddr()` for more.
WithRemoteAddrHeader(headerName string) Configurator // enables a header.
WithoutRemoteAddrHeader(headerName string) Configurator // disables a header.

For example, if you want to enable the "CF-Connecting-IP" header (cloudflare)
you have to add the WithRemoteAddrHeader option to the app.Run function, at the end of your program.

app.Run(iris.Addr(":8080"), iris.WithRemoteAddrHeader("CF-Connecting-IP"))
// This header name will be checked when ctx.RemoteAddr() called and if exists
// it will return the client's IP, otherwise it will return the default *http.Request's `RemoteAddr` field.

Miscellaneous

Fix typescript tools.

_examples folder has been ordered by feature and usage:
- contains tests on some examples
- new examples added, one of them shows how the reuseport feature on UNIX and BSD systems can be used to listen for incoming connections, see here

Replace supervisor's tasks with events, like RegisterOnShutdown, RegisterOnError, RegisterOnServe and fix the (unharmful) race condition when output the banner to the console. Global notifier for interrupt signals which can be disabled via app.Run([...], iris.WithoutInterruptHandler), look graceful-shutdown example for more.

More handlers are ported to Iris (they can be used as they are without iris.FromStd), these handlers can be found at iris-contrib/middleware. Feel free to put your own there.

Middleware Description Example
jwt Middleware checks for a JWT on the Authorization header on incoming requests and decodes it. iris-contrib/middleware/jwt/_example
cors HTTP Access Control. iris-contrib/middleware/cors/_example
secure Middleware that implements a few quick security wins. iris-contrib/middleware/secure/_example
tollbooth Generic middleware to rate-limit HTTP requests. iris-contrib/middleware/tollbooth/_examples/limit-handler
cloudwatch AWS cloudwatch metrics middleware. iris-contrib/middleware/cloudwatch/_example
new relic Official New Relic Go Agent. iris-contrib/middleware/newrelic/_example
prometheus Easily create metrics endpoint for the prometheus instrumentation tool iris-contrib/middleware/prometheus/_example

v7.x is deprecated because it sold as it is and it is not part of the public, stable gopkg.in iris versions. Developers/users of this library should upgrade their apps to v8.x, the refactor process will cost nothing for most of you, as the most common API remains as it was. The changelog history from that are being presented below.

Th, 15 June 2017 | v7.2.0

About our new home page

https://iris-go.com

Thanks to Santosh Anand the https://iris-go.com has been upgraded and it's really awesome!

Santosh is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him.

The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!

Cache

Declare the iris.Cache alias to the new, improved and most-suited for common usage, cache.Handler function.

iris.Cache be used as middleware in the chain now, example here. However you can still use the cache as a wrapper by importing the github.com/kataras/iris/cache package.

File server

  • Fix that.

  • app.StaticHandler(requestPath string, systemPath string, showList bool, gzip bool) -> app.StaticHandler(systemPath,showList bool, gzip bool)

  • New feature for Single Page Applications, app.SPA(assetHandler context.Handler) implemented.

  • New app.StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) added in order to be able to pass that on app.SPA(app.StaticEmbeddedHandler("./public", Asset, AssetNames)).

  • Fix app.StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string).

Examples:

app.StaticWeb doesn't works for root request path "/" anymore, use the new app.SPA instead.

WWW subdomain entry

  • Example added to copy all application's routes, including parties, to the www.mydomain.com

Wrapping the Router

  • Example added to show you how you can use the app.WrapRouter
    to implement a similar to app.SPA functionality, don't panic, it's easier than it sounds.

Testing

  • httptest.New(app *iris.Application, t *testing.T) -> httptest.New(t *testing.T, app *iris.Application).

  • New httptest.NewLocalListener() net.Listener added.

  • New httptest.NewLocalTLSListener(tcpListener net.Listener) net.Listener added.

Useful for testing tls-enabled servers:

Proxies are trying to understand local addresses in order to allow InsecureSkipVerify.

  • host.ProxyHandler(target *url.URL) *httputil.ReverseProxy.

  • host.NewProxy(hostAddr string, target *url.URL) *Supervisor.

    Tests here.

Tu, 13 June 2017 | v7.1.1

Fix that.

Mo, 12 June 2017 | v7.1.0

Fix that.

Su, 11 June 2017 | v7.0.5

Iris now supports static paths and dynamic paths for the same path prefix with zero performance cost:

app.Get("/profile/{id:int}", handler) and app.Get("/profile/create", createHandler) are not in conflict anymore.

The rest of the special Iris' routing features, including static & wildcard subdomains are still work like a charm.

This was one of the most popular community's feature requests. Click here to see a trivial example.

Sa, 10 June 2017 | v7.0.4

  • Simplify and add a test for the basicauth middleware, no need to be
    stored inside the Context anymore, developers can get the validated user(username and password) via context.Request().BasicAuth(). basicauth.Config.ContextKey was removed, just remove that field from your configuration, it's useless now.

Sa, 10 June 2017 | v7.0.3

  • New context.Session().PeekFlash("key") added, unlike GetFlash this will return the flash value but keep the message valid for the next requests too.
  • Complete the httptest example.
  • Fix the (marked as deprecated) ListenLETSENCRYPT function.
  • Upgrade the iris-contrib/middleware including JWT, CORS and Secure handlers.
  • Add OAuth2 example -- showcases the third-party package goth integration with Iris.

Community

Th, 08 June 2017 | v7.0.2

  • Able to set immutable data on sessions and context's storage. Aligned to fix an issue on slices and maps as reported here.

We, 07 June 2017 | v7.0.1

  • Proof of concept of an internal release generator, navigate here to read more.
  • Remove tray icon "feature", click here to learn why.

Sa, 03 June 2017

After 2+ months of hard work and collaborations, Iris version 7 was published earlier today.

If you're new to Iris you don't have to read all these, just navigate to the updated examples and you should be fine:)

Note that this section will not
cover the internal changes, the difference is so big that anybody can see them with a glimpse, even the code structure itself.

Changes from v6

The whole framework was re-written from zero but I tried to keep the most common public API that iris developers use.

Vendoring /w update

The previous vendor action for v6 was done by-hand, now I'm using the go dep tool, I had to do
some small steps:

  • remove files like testdata to reduce the folder size
  • rollback some of the "golang/x/net/ipv4" and "ipv6" source files because they are downloaded to their latest versions
    by go dep, but they had lines with the typealias feature, which is not ready by current golang version (it will be on August)
  • fix "cannot use internal package" at golang/x/net/ipv4 and ipv6 packages
    • rename the interal folder to was-internal, everywhere and fix its references.
  • fix "main redeclared in this block"
    • remove all examples folders.
  • remove main.go files on jsondiff lib, used by gavv/httpexpect, produces errors on test -v ./... while jd and jp folders are not used at all.

The go dep tool does what is says, as expected, don't be afraid of it now.
I am totally recommending this tool for package authors, even if it's in its alpha state.
I remember when Iris was in its alpha state and it had 4k stars on its first weeks/or month and that helped me a lot to fix reported bugs by users and make the framework even better, so give love to go dep from today!

General

  • Several enhancements for the typescript transpiler, view engine, websocket server and sessions manager
  • All Listen methods replaced with a single Run method, see here
  • Configuration, easier to modify the defaults, see here
  • HandlerFunc removed, just Handler of func(context.Context) where context.Context derives from import "github.com/kataras/iris/context" (NEW: this import path is optional, use iris.Context if you've installed Go 1.9)
    • Simplify API, i.e: instead of Handle,HandleFunc,Use,UseFunc,Done,DoneFunc,UseGlobal,UseGlobalFunc use Handle,Use,Done,UseGlobal.
  • Response time decreased even more (9-35%, depends on the application)
  • The Adaptors idea replaced with a more structural design pattern, but you have to apply these changes:
    • app.Adapt(view.HTML/Pug/Amber/Django/Handlebars...) -> app.AttachView(view.HTML/Pug/Amber/Django/Handlebars...)
    • app.Adapt(sessions.New(...)) -> app.AttachSessionManager(sessions.New(...))
    • app.Adapt(iris.LoggerPolicy(...)) -> app.AttachLogger(io.Writer)
    • app.Adapt(iris.RenderPolicy(...)) -> removed and replaced with the ability to replace the whole context with a custom one or override some methods of it, see below.

Routing

  • Remove of multiple routers, now we have the fresh Iris router which is based on top of the julien's httprouter.

    Update 11 June 2017: As of 7.0.5 this is changed, read here.

  • Subdomains routing algorithm has been improved.
  • Iris router is using a custom interpreter with parser and path evaluator to achieve the best expressiveness, with zero performance loss, you ever seen so far, i.e:
    • app.Get("/", "/users/{userid:int min(1)}", handler),
      • {username:string} or just {username}
      • {asset:path},
      • {firstname:alphabetical},
      • {requestfile:file} ,
      • {mylowercaseParam regexp([a-z]+)}.
      • The previous syntax of :param and *param still working as expected. Previous rules for paths confliction remain as they were.
        • Also, path parameter names should be only alphabetical now, numbers and symbols are not allowed (for your own good, I have seen a lot the last year...).

Click here for details.

It was my first attempt/experience on the interpreters field, so be good with it :)

Context

  • iris.Context pointer replaced with context.Context interface as we already mention
    • in order to be able to use a custom context and/or catch lifetime like BeginRequest and EndRequest from context itself, see below
  • context.JSON, context.JSONP, context.XML, context.Markdown, context.HTML work faster
  • context.Render("filename.ext", bindingViewData{}, options) -> context.View("filename.ext")
    • View renders only templates, it will not try to search if you have a restful renderer adapted, because, now, you can do it via method overriding using a custom Context.
    • Able to set context.ViewData and context.ViewLayout via middleware when executing a template.
  • context.SetStatusCode(statusCode) -> context.StatusCode(statusCode)
    • which is equivalent with the old EmitError too:
      • if status code >=400 given can automatically fire a custom http error handler if response wasn't written already.
    • context.StatusCode() -> context.GetStatusCode()
    • app.OnError -> app.OnErrorCode
    • Errors per party are removed by-default, you can just use one global error handler with logic like "if path starts with 'prefix' fire this error handler, else...".
  • Easy way to change Iris' default Context with a custom one, see here
  • context.ResponseWriter().SetBeforeFlush(...) works for Flush and HTTP/2 Push, respectfully
  • Several improvements under the Request transactions
  • Remember that you had to set a status code on each of the render-relative methods? Now it's not required, it just renders
    with the status code that user gave with context.StatusCode or with 200 OK, i.e:
    -context.JSON(iris.StatusOK, myJSON{}) -> context.JSON(myJSON{}).
    • Each one of the context's render methods has optional per-call settings,
    • the new API is even more easier to read, understand and use.

Server

  • Able to set custom underline *http.Server(s) with new Host (aka Server Supervisor) feature
    • Done and Err channels to catch shutdown or any errors on custom hosts,
    • Schedule custom tasks(with cancelation) when server is running, see here
  • Interrupt handler task for gracefully shutdown (when CTRL/CMD+C) are enabled by-default, you can disable its via configuration: app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler)

Future plans

  • Future Go1.9's ServeTLS is ready when 1.9 released
  • Future Go1.9's typealias feature is ready when 1.9 released, i.e context.Context -> iris.Context just one import path instead of todays' two.

v8.4.4

@kataras kataras released this Oct 1, 2017 · 295 commits to master since this release

FAQ

https://github.com/kataras/iris/blob/master/faq.md

History

Iris uses the vendor directory feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes.

Su, 01 October 2017 | v8.4.4

  • Fix #762 reported by @xkylsoft
  • Fix #771 reported by @cdren
  • Improvements to the memstore's GetInt, GetInt64, GetFloat64, GetBool and remove the golang/net/context's interface completion from Context, read the changes for more
  • Add two examples for folder structuring as requested at #748
  • Add node.js express benchmarks similar to iris and netcore

We, 27 September 2017 | v8.4.3

Fr, 15 September 2017 | v8.4.2

MVC

Support more than one dynamic method function receivers.

package main

import "github.com/kataras/iris"

func main() {
    app := iris.New()
    app.Controller("/user", new(UserController))
    app.Run(iris.Addr("localhost:8080"))
}

type UserController struct { iris.Controller }

// Maps to GET /user
// Request example: http://localhost:8080/user
// as usual.
func (c *UserController) Get() {
    c.Text = "hello from /user"
}

// Maps to GET /user/{paramfirst:long}
// Request example: http://localhost:8080/user/42
// as usual.
func (c *UserController) GetBy(userID int64) {
    c.Ctx.Writef("hello user with id: %d", userID)
}

// NEW:
// Maps to GET /user/{paramfirst:long}/business/{paramsecond:long}
// Request example: http://localhost:8080/user/42/business/93
func (c *UserController) GetByBusinessBy(userID int64, businessID int64) {
    c.Ctx.Writef("fetch a business id: %d that user with id: %d owns, may make your db query faster",
    businessID, userID)
}

Th, 07 September 2017 | v8.4.1

Routing

Add a macro type for booleans: app.Get("/mypath/{paramName:boolean}", myHandler).

+------------------------+
| {param:boolean}        |
+------------------------+
bool type
only "1" or "t" or "T" or "TRUE" or "true" or "True"
or "0" or "f" or "F" or "FALSE" or "false" or "False"

Add context.Params().GetBool(paramName string) (bool, error) respectfully.

app := iris.New()
app.Get("/mypath/{has:boolean}", func(ctx iris.Context) { // <--
    // boolean first return value
    // error as second return value
    //
    // error will be always nil here because
    // we use the {has:boolean} so router
    // makes sure that the parameter is a boolean
    // otherwise it will return a 404 not found http error code
    // skipping the call of this handler.
    has, _ := ctx.Params().GetBool("has") // <--
    if has {
        ctx.HTML("<strong>it's true</strong>")
    }else {
        ctx.HTML("<strong>it's false</string>")
    }
})
// [...]

MVC

Support for boolean method receivers, i.e GetBy(bool), PostBy(bool)....

app := iris.New()

app.Controller("/equality", new(Controller))
type Controller struct {
    iris.Controller
}

// handles the "/equality" path.
func (c *Controller) Get() {

}

// registers and handles the path: "/equality/{param:boolean}".
func (c *Controller) GetBy(is bool) { // <--
    // [...]
}

Supported types for method functions receivers are: int, int64, bool and string.

Su, 27 August 2017 | v8.4.0

Miscellaneous

Router

Add a new macro type for path parameters, long, it's the go type int64.

app.Get("/user/{id:long}", func(ctx context.Context) {
	userID, _ := ctx.Params().GetInt64("id")
})

MVC

The ability to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that after a go get -u github.com/kataras/iris you will be able to use things like these:

If app.Controller("/user", new(user.Controller))

  • func(*Controller) Get() - GET:/user , as usual.
  • func(*Controller) Post() - POST:/user, as usual.
  • func(*Controller) GetLogin() - GET:/user/login
  • func(*Controller) PostLogin() - POST:/user/login
  • func(*Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(*Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(*Controller) GetBy(id int64) - GET:/user/{param:long}
  • func(*Controller) PostBy(id int64) - POST:/user/{param:long}

If app.Controller("/profile", new(profile.Controller))

  • func(*Controller) GetBy(username string) - GET:/profile/{param:string}

If app.Controller("/assets", new(file.Controller))

  • func(*Controller) GetByWildard(path string) - GET:/assets/{param:path}

Example can be found at: _examples/mvc/login/user/controller.go.

Pretty awesome, right?

We, 23 August 2017 | v8.3.4

Give read access to the current request context's route, a feature that many of you asked a lot.

func(ctx context.Context) {
	_ = ctx.GetCurrentRoute().Name()
	//					.Method() returns string, same as ctx.Method().
	//					.Subdomain() returns string, the registered subdomain.
	//					.Path() returns string, the registered path.
	//					.IsOnline() returns boolean.
}
type MyController struct {
	mvc.Controller
}

func (c *MyController) Get(){
	_ = c.Route().Name() // same as `c.Ctx.GetCurrentRoute().Name()`.
	// [...]
}

Updated: 24 August 2017

This evening, on the next version 8.3.5:

Able to pre-calculate, register and map different (relative) paths inside a single controller
with zero performance cost.

Meaning that in the future you will be able to use something like these:

If app.Controller("/user", new(user.Controller))

  • func(c *Controller) Get() - GET:/user , as usual.
  • func(c *Controller) Post() - POST:/user, as usual.
  • func(c *Controller) GetLogin() - GET:/user/login
  • func(c *Controller) PostLogin() - POST:/user/login
  • func(c *Controller) GetProfileFollowers() - GET:/user/profile/followers
  • func(c *Controller) PostProfileFollowers() - POST:/user/profile/followers
  • func(c *Controller) GetBy() - GET:/user/{param}
  • func(c *Controller) GetByName(name string) - GET:/user/{name}
  • func(c *Controller) PostByName(name string) - POST:/user/{name}
  • func(c *Controller) GetByID(id int64 || int) - GET:/user/{id:int}
  • func(c *Controller) PostByID(id int64 || int) - POST:/user/{id:int}

Watch and stay tuned my friends.

We, 23 August 2017 | v8.3.3

Better debug messages when using MVC.

Add support for recursively binding and custom controllers embedded to other custom controller, that's the new feature. That simply means that Iris users are able to use "shared" controllers everywhere; when binding, using models, get/set persistence data, adding middleware, intercept request flow.

This will help web authors to split the logic at different controllers. Those controllers can be also used as "standalone" to serve a page somewhere else in the application as well.

My personal advice to you is to always organize and split your code nicely and wisely in order to avoid using such as an advanced MVC feature, at least any time soon.

I'm aware that this is not always an easy task to do, therefore is here if you ever need it :)

A ridiculous simple example of this feature can be found at the mvc/controller_test.go file.

Tu, 22 August 2017 | v8.3.2

MVC

When one or more values of handler type (func(ctx context.Context)) are passed
right to the controller initialization then they will be recognised and act as middleware(s)
that ran even before the controller activation, there is no reason to load
the whole controller if the main handler or its BeginRequest are not "allowed" to be executed.

Example Code

func checkLogin(ctx context.Context) {
	if !myCustomAuthMethodPassed {
		// [set a status or redirect, you know what to do]
		ctx.StatusCode(iris.StatusForbidden)
		return
	}

	// [continue to the next handler, at this example is our controller itself]
	ctx.Next()
}

// [...]
app.Controller(new(ProfileController), checkLogin)
// [...]

Usage of these kind of MVC features could be found at the mvc/controller_test.go file.

Other minor enhancements

  • fix issue #726*
  • fix redis sessiondb expiration*
  • update recursively when new version is available*
  • some minor session enhancements*

Sa, 19 August 2017 | v8.3.1

First of all I want to thank you for the 100% green feedback you gratefully sent me you about
my latest article Go vs .NET Core in terms of HTTP performance, published at medium's hackernoon.com and dev.to. I really appreciate it💓

No API Changes.

However two more methods added to the Controller.

  • RelPath() string, returns the relative path based on the controller's name and the request path.
  • RelTmpl() string, returns the relative template directory based on the controller's name.

These are useful when dealing with big controllers, they help you to keep align with any
future changes inside your application.

Let's refactor our ProfileController enhancemed by these two new functions.

func (pc *ProfileController) tmpl(relativeTmplPath string) {
	// the relative template files directory of this controller.
	views := pc.RelTmpl()
	pc.Tmpl = views + relativeTmplPath
}

func (pc *ProfileController) match(relativeRequestPath string) bool {
	// the relative request path of this controller.
	path := pc.RelPath()
	return path == relativeRequestPath
}

func (pc *ProfileController) Get() {
	// requested: "/profile"
	// so relative path is "/" because of the ProfileController.
	if pc.match("/") {

		// views/profile/index.html
		pc.tmpl("index.html")
		return
	}

	// requested: "/profile/browse"
	// so relative path is "/browse".
	if pc.match("/browse") {
		pc.Path = "/profile"
		return
	}

	// requested: "/profile/me"
	// so the relative path is "/me"
	if pc.match("/me") {
		
		// views/profile/me.html
		pc.tmpl("me.html")
		return
	}

	// requested: "/profile/$ID"
	// so the relative path is "/$ID"
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound

		// views/profile/notfound.html
		pc.tmpl("notfound.html")
		pc.Data["ID"] = id
		return
	}

	// views/profile/profile.html
	pc.tmpl("profile.html")
	pc.User = user
}

Want to learn more about these functions? Go to the mvc/controller_test.go file and scroll to the bottom!

Fr, 18 August 2017 | v8.3.0

Good news for devs that are used to write their web apps using the MVC architecture pattern.

Implement a whole new mvc package with additional support for models and easy binding.

@kataras started to develop that feature by version 8.2.5, back then it didn't seem
to be a large feature and maybe a game-changer, so it lived inside the kataras/iris/core/router/controller.go file.
However with this version, so many things are implemented for the MVC and we needed a new whole package,
this new package is the kataras/iris/mvc, but if you used go 1.9 to build then you don't have to do any refactor, you could use the iris.Controller type alias.

People who used the mvc from its baby steps(v8.2.5) the only syntactic change you'll have to do is to rename the router.Controller to mvc.Controller:

Before:

import "github.com/kataras/iris/core/router"
type MyController struct {
    router.Controller
}

Now:

import "github.com/kataras/iris/mvc"
type MyController struct {
    mvc.Controller
    // if you build with go1.9 you can omit the import of mvc package
    // and just use `iris.Controller` instead.
}

MVC (Model View Controller)

From version 8.3 and after Iris has first-class support for the MVC pattern, you'll not find
these stuff anywhere else in the Go world.

Example Code

package main

import (
	"sync"

	"github.com/kataras/iris"
	"github.com/kataras/iris/mvc"
)

func main() {
	app := iris.New()
	app.RegisterView(iris.HTML("./views", ".html"))

	// when we have a path separated by spaces
	// then the Controller is registered to all of them one by one.
	//
	// myDB is binded to the controller's `*DB` field: use only structs and pointers.
	app.Controller("/profile /profile/browse /profile/{id:int} /profile/me",
		new(ProfileController), myDB) // IMPORTANT

	app.Run(iris.Addr(":8080"))
}

// UserModel our example model which will render on the template.
type UserModel struct {
	ID       int64
	Username string
}

// DB is our example database.
type DB struct {
	usersTable map[int64]UserModel
	mu         sync.RWMutex
}

// GetUserByID imaginary database lookup based on user id.
func (db *DB) GetUserByID(id int64) (u UserModel, found bool) {
	db.mu.RLock()
	u, found = db.usersTable[id]
	db.mu.RUnlock()
	return
}

var myDB = &DB{
	usersTable: map[int64]UserModel{
		1:  {1, "kataras"},
		2:  {2, "makis"},
		42: {42, "jdoe"},
	},
}

// ProfileController our example user controller which controls
// the paths of "/profile" "/profile/{id:int}" and "/profile/me".
type ProfileController struct {
	mvc.Controller // IMPORTANT

	User UserModel `iris:"model"`
	// we will bind it but you can also tag it with`iris:"persistence"`
	// and init the controller with manual &PorifleController{DB: myDB}.
	DB *DB
}

// Get method handles all "GET" HTTP Method requests of the controller's paths.
func (pc *ProfileController) Get() { // IMPORTANT
	path := pc.Path

	// requested: /profile path
	if path == "/profile" {
		pc.Tmpl = "profile/index.html"
		return
	}
	// requested: /profile/browse
	// this exists only to proof the concept of changing the path:
	// it will result to a redirection.
	if path == "/profile/browse" {
		pc.Path = "/profile"
		return
	}

	// requested: /profile/me path
	if path == "/profile/me" {
		pc.Tmpl = "profile/me.html"
		return
	}

	// requested: /profile/$ID
	id, _ := pc.Params.GetInt64("id")

	user, found := pc.DB.GetUserByID(id)
	if !found {
		pc.Status = iris.StatusNotFound
		pc.Tmpl = "profile/notfound.html"
		pc.Data["ID"] = id
		return
	}

	pc.Tmpl = "profile/profile.html"
	pc.User = user
}


/*
func (pc *ProfileController) Post() {}
func (pc *ProfileController) Put() {}
func (pc *ProfileController) Delete() {}
func (pc *ProfileController) Connect() {}
func (pc *ProfileController) Head() {}
func (pc *ProfileController) Patch() {}
func (pc *ProfileController) Options() {}
func (pc *ProfileController) Trace() {}
*/

/*
func (pc *ProfileController) All() {}
//        OR
func (pc *ProfileController) Any() {}
*/

Iris web framework supports Request data, Models, Persistence Data and Binding
with the fastest possible execution.

Characteristics

All HTTP Methods are supported, for example if want to serve GET
then the controller should have a function named Get(),
you can define more than one method function to serve in the same Controller struct.

Persistence data inside your Controller struct (share data between requests)
via iris:"persistence" tag right to the field or Bind using app.Controller("/" , new(myController), theBindValue).

Models inside your Controller struct (set-ed at the Method function and rendered by the View)
via iris:"model" tag right to the field, i.e User UserModel `iris:"model" name:"user"` view will recognise it as {{.user}}.
If name tag is missing then it takes the field's name, in this case the "User".

Access to the request path and its parameters via the Path and Params fields.

Access to the template file that should be rendered via the Tmpl field.

Access to the template data that should be rendered inside
the template file via Data field.

Access to the template layout via the Layout field.

Access to the low-level context.Context via the Ctx field.

Get the relative request path by using the controller's name via RelPath().

Get the relative template path directory by using the controller's name via RelTmpl().

Flow as you used to, Controllers can be registered to any Party,
including Subdomains, the Party's begin and done handlers work as expected.

Optional BeginRequest(ctx) function to perform any initialization before the method execution,
useful to call middlewares or when many methods use the same collection of data.

Optional EndRequest(ctx) function to perform any finalization after any method executed.

Inheritance, recursively, see for example our mvc.SessionController, it has the mvc.Controller as an embedded field
and it adds its logic to its BeginRequest, here.

Read access to the current route via the Route field.

Using Iris MVC for code reuse

By creating components that are independent of one another, developers are able to reuse components quickly and easily in other applications. The same (or similar) view for one application can be refactored for another application with different data because the view is simply handling how the data is being displayed to the user.

If you're new to back-end web development read about the MVC architectural pattern first, a good start is that wikipedia article.

Follow the examples below,

Bugs

Fix #723 reported by @speedwheel.

Mo, 14 August 2017 | v8.2.6

Able to call done/end handlers inside a Controller, via optional EndRequest(ctx context.Context) function inside the controller struct.

// it's called after t.Get()/Post()/Put()/Delete()/Connect()/Head()/Patch()/Options()/Trace().
func (t *testControllerEndRequestFunc) EndRequest(ctx context.Context) {
    // 2.
    // [your code goes here...]
}

// will handle "GET" request HTTP method only.
func (t *testControllerEndRequestFunc) Get() {
    // 1.
    // [your code goes here...]
}

Look at the v8.2.5 changelog to learn more about the new Iris Controllers feature.

Su, 13 August 2017 | v8.2.5

Good news for devs that are used to write their web apps using the MVC-style app architecture.

Yesterday I wrote a tutorial on how you can transform your raw Handlers to Controllers using the existing tools only (Iris is the most modular web framework out there, we all have no doubt about this).

Today, I did implement the Controller idea as built'n feature inside Iris.
Our Controller supports many things among them are:

  • all HTTP Methods are supported, for example if want to serve GET then the controller should have a function named Get(), you can define more than one method function to serve in the same Controller struct
  • persistence data inside your Controller struct (share data between requests) via iris:"persistence" tag right to the field
  • optional BeginRequest(ctx) function to perform any initialization before the methods, useful to call middlewares or when many methods use the same collection of data
  • optional EndRequest(ctx) function to perform any finalization after the methods executed
  • access to the request path parameters via the Params field
  • access to the template file that should be rendered via the Tmpl field
  • access to the template data that should be rendered inside the template file via Data field
  • access to the template layout via the Layout field
  • access to the low-level context.Context via the Ctx field
  • flow as you used to, Controllers can be registered to any Party, including Subdomains, the Party's begin and done handlers work as expected.

It's very easy to get started, the only function you need to call instead of app.Get/Post/Put/Delete/Connect/Head/Patch/Options/Trace is the app.Controller.

Example Code:

// file: main.go

package main

import (
    "github.com/kataras/iris"

    "controllers"
)

func main() {
    app := iris.New()
    app.RegisterView(iris.HTML("./views", ".html"))

    app.Controller("/", new(controllers.Index))

    // http://localhost:8080/
    app.Run(iris.Addr(":8080"))
}
// file: controllers/index.go

package controllers

import (
    "github.com/kataras/iris/core/router"
)

// Index is our index example controller.
type Index struct {
    mvc.Controller
    // if you're using go1.9: 
    // you can omit the /core/router import statement
    // and just use the `iris.Controller` instead.
}

// will handle GET method on http://localhost:8080/
func (c *Index) Get() {
    c.Tmpl = "index.html"
    c.Data["title"] = "Index page"
    c.Data["message"] = "Hello world!"
}

// will handle POST method on http://localhost:8080/
func (c *Index) Post() {}

Tip: declare a func(c *Index) All() {} or Any() to register all HTTP Methods.

A full example can be found at the _examples/mvc folder.

Sa, 12 August 2017 | v8.2.4

No API Changes.

Fix #717, users are welcomed to follow the thread for any questions or reports about Gzip and Static Files Handlers only.

Th, 10 August 2017 | v8.2.3

No API Changes.

Fix #714

Continue to v8.2.2 for more...

Th, 10 August 2017 | v8.2.2

No API Changes.

  • Implement Google reCAPTCHA middleware, example here
  • Fix kataras/golog prints with colors on windows server 2012 while it shouldn't because its command line tool does not support 256bit colors
  • Improve the updater by a custom self-updated back-end version checker, can be disabled by:
app.Run(iris.Addr(":8080"), iris.WithoutVersionChecker)

Or

app.Configure(iris.WithoutVersionChecker)

Or

app.Configure(iris.WithConfiguration(iris.Configuration{DisableVersionChecker:true}))

Tu, 08 August 2017 | v8.2.1

No API Changes. Great news for the unique iris sessions library, once again.

NEW: LevelDB-based session database implemented, example here.

Redis-based sessiondb has no longer the MaxAgeSeconds config field,
this is passed automatically by the session manager, now.

All sessions databases have an Async(bool) function, if turned on
then all synchronization between the memory store and the back-end database will happen
inside different go routines. By-default async is false but it's recommended to turn it on, it will make sessions to be stored faster, at most.

All reported issues have been fixed, the API is simplified by v8.2.0 so everyone can
create and use any back-end storage for application's sessions persistence.

Mo, 07 August 2017 | v8.2.0

No Common-API Changes.

Good news for iris sessions back-end databases users.

Info for session database authors Session Database API Changed to:
type Database interface {
	Load(sid string) RemoteStore
	Sync(p SyncPayload)
}

// SyncPayload reports the state of the session inside a database sync action.
type SyncPayload struct {
	SessionID string

	Action Action
	// on insert it contains the new key and the value
	// on update it contains the existing key and the new value
	// on delete it contains the key (the value is nil)
	// on clear it contains nothing (empty key, value is nil)
	// on destroy it contains nothing (empty key, value is nil)
	Value memstore.Entry
	// Store contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Store RemoteStore
}


// RemoteStore is a helper which is a wrapper
// for the store, it can be used as the session "table" which will be
// saved to the session database.
type RemoteStore struct {
	// Values contains the whole memory store, this store
	// contains the current, updated from memory calls,
	// session data (keys and values). This way
	// the database has access to the whole session's data
	// every time.
	Values memstore.Store
	// on insert it contains the expiration datetime
	// on update it contains the new expiration datetime(if updated or the old one)
	// on delete it will be zero
	// on clear it will be zero
	// on destroy it will be zero
	Lifetime LifeTime
}

Read more at sessions/database.go, view how three built'n session databases are being implemented here.

All sessions databases are updated and they performant even faster than before.

  • NEW raw file-based session database implemented, example here
  • NEW boltdb-based session database implemented, example here (recommended as it's safer and faster)
  • redis sessiondb updated to the latest api

Under the cover, session database works entirely differently than before but nothing changed from the user's perspective, so upgrade with go get -u github.com/kataras/iris and sleep well.

Tu, 01 August 2017 | v8.1.3

  • Add Option function to the html view engine: #694
  • Fix sessions backend databases restore expiration: #692 by @corebreaker
  • Add PartyFunc, same as Party but receives a function with the sub router as its argument instead [GO1.9 Users-ONLY]

Mo, 31 July 2017 | v8.1.2

Add a ConfigureHost function as an alternative way to customize the hosts via host.Configurator.
The first way was to pass host.Configurator as optional arguments on iris.Runners built'n functions (iris#Server, iris#Listener, iris#Addr, iris#TLS, iris#AutoTLS), example of this can be found there.

Example Code:

package main

import (
	stdContext "context"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/core/host"
)

func main() {
	app := iris.New()

	app.Get("/", func(ctx context.Context) {
		ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
	})

    app.ConfigureHost(configureHost) // or pass "configureHost" as `app.Addr` argument, same result.

	app.Logger().Info("Wait 10 seconds and check your terminal again")
	// simulate a shutdown action here...
	go func() {
		<-time.After(10 * time.Second)
		timeout := 5 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		// close all hosts, this will notify the callback we had register
		// inside the `configureHost` func.
		app.Shutdown(ctx)
	}()

	// http://localhost:8080
	// wait 10 seconds and check your terminal.
	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
}

func configureHost(su *host.Supervisor) {
	// here we have full access to the host that will be created
	// inside the `app.Run` or `app.NewHost` function .
	//
	// we're registering a shutdown "event" callback here:
	su.RegisterOnShutdown(func() {
		println("server is closed