diff --git a/_examples/README.md b/_examples/README.md
index 1a1df09a..5b50e7c9 100644
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -1,370 +1,195 @@
-# Examples
-
-Please do learn how [net/http](https://golang.org/pkg/net/http/) std package works, first.
-
-This folder provides easy to understand code snippets on how to get started with [iris](https://github.com/kataras/iris) web framework.
-
-It doesn't always contain the "best ways" but it does cover each important feature that will make you so excited to GO with iris!
-
-## Running the examples
-
-
-
-1. Install the Go Programming Language, version 1.12+ from https://golang.org/dl.
-2. [Install Iris](https://github.com/kataras/iris/wiki/installation)
-3. Install any external packages that required by the examples
-
-
-External packages
-
-```sh
-cd _examples && go get ./...
-```
-
-
-
-And run each example you wanna see, e.g.
-
-```sh
-$ cd $GOPATH/src/github.com/kataras/iris/_examples/overview
-$ go run main.go
-```
-
-> Test the examples by opening a terminal window and execute: `go test -v ./...`
-
-### Overview
-
-- [Hello world!](hello-world/main.go)
-- [Docker](docker/README.md)
-- [Hello WebAssembly!](webassembly/basic/main.go)
-- [Glimpse](overview/main.go)
-- [Tutorial: Online Visitors](tutorial/online-visitors/main.go)
-- [Tutorial: A Todo MVC Application using Iris and Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064)
-- [Tutorial: URL Shortener using BoltDB](https://medium.com/@kataras/a-url-shortener-service-using-go-iris-and-bolt-4182f0b00ae7)
-- [Tutorial: How to turn your Android Device into a fully featured Web Server (**MUST**)](https://twitter.com/ThePracticalDev/status/892022594031017988)
-- [POC: Convert the medium-sized project "Parrot" from native to Iris](https://github.com/iris-contrib/parrot)
-- [POC: Isomorphic react/hot reloadable/redux/css-modules starter kit](https://github.com/kataras/iris-starter-kit)
-- [Tutorial: DropzoneJS Uploader](tutorial/dropzonejs)
-- [Tutorial: Caddy](tutorial/caddy)
-- [Tutorial:Iris Go Framework + MongoDB](https://medium.com/go-language/iris-go-framework-mongodb-552e349eab9c)
-- [Tutorial: API for Apache Kafka](tutorial/api-for-apache-kafka)
-
-### Structuring
-
-Nothing stops you from using your favorite folder structure. Iris is a low level web framework, it has got MVC first-class support but it doesn't limit your folder structure, this is your choice.
-
-Structuring depends on your own needs. We can't tell you how to design your own application for sure but you're free to take a closer look to the examples below; you may find something useful that you can borrow for your app;
-
-- [Bootstrapper](structuring/bootstrap)
-- [MVC with Repository and Service layer Overview](structuring/mvc-plus-repository-and-service-layers)
-- [Login (MVC with Single Responsibility package)](structuring/login-mvc-single-responsibility-package)
-- [Login (MVC with Datamodels, Datasource, Repository and Service layer)](structuring/login-mvc)
-
-### HTTP Listening
-
-- [Common, with address](http-listening/listen-addr/main.go)
- * [public domain address](http-listening/listen-addr-public/main.go)
- * [omit server errors](http-listening/listen-addr/omit-server-errors/main.go)
-- [UNIX socket file](http-listening/listen-unix/main.go)
-- [TLS](http-listening/listen-tls/main.go)
-- [Letsencrypt (Automatic Certifications)](http-listening/listen-letsencrypt/main.go)
-- [Notify on shutdown](http-listening/notify-on-shutdown/main.go)
-- Custom TCP Listener
- * [common net.Listener](http-listening/custom-listener/main.go)
- * [SO_REUSEPORT for unix systems](http-listening/custom-listener/unix-reuseport/main.go)
-- Custom HTTP Server
- * [HTTP/3 Quic](http-listening/http3-quic)
- * [easy way](http-listening/custom-httpserver/easy-way/main.go)
- * [std way](http-listening/custom-httpserver/std-way/main.go)
- * [multi server instances](http-listening/custom-httpserver/multi/main.go)
-- Graceful Shutdown
- * [using the `RegisterOnInterrupt`](http-listening/graceful-shutdown/default-notifier/main.go)
- * [using a custom notifier](http-listening/graceful-shutdown/custom-notifier/main.go)
-
-### Configuration
-
-- [Functional](configuration/functional/main.go)
-- [From Configuration Struct](configuration/from-configuration-structure/main.go)
-- [Import from YAML file](configuration/from-yaml-file/main.go)
- * [Share Configuration between multiple instances](configuration/from-yaml-file/shared-configuration/main.go)
-- [Import from TOML file](configuration/from-toml-file/main.go)
-
-### Routing, Grouping, Dynamic Path Parameters, "Macros" and Custom Context
-
-* `app.Get("{userid:int min(1)}", myHandler)`
-* `app.Post("{asset:path}", myHandler)`
-* `app.Put("{custom:string regexp([a-z]+)}", myHandler)`
-
-Note: unlike other routers you'd seen, iris' router can handle things like these:
-```go
-// Matches all GET requests prefixed with "/assets/"
-app.Get("/assets/{asset:path}", assetsWildcardHandler)
-
-// Matches only GET "/"
-app.Get("/", indexHandler)
-// Matches only GET "/about"
-app.Get("/about", aboutHandler)
-
-// Matches all GET requests prefixed with "/profile/"
-// and followed by a single path part
-app.Get("/profile/{username:string}", userHandler)
-// Matches only GET "/profile/me" because
-// it does not conflict with /profile/{username:string}
-// or the root wildcard {root:path}
-app.Get("/profile/me", userHandler)
-
-// Matches all GET requests prefixed with /users/
-// and followed by a number which should be equal or bigger than 1
-app.Get("/user/{userid:int min(1)}", getUserHandler)
-// Matches all requests DELETE prefixed with /users/
-// and following by a number which should be equal or bigger than 1
-app.Delete("/user/{userid:int min(1)}", deleteUserHandler)
-
-// Matches all GET requests except "/", "/about", anything starts with "/assets/" etc...
-// because it does not conflict with the rest of the routes.
-app.Get("{root:path}", rootWildcardHandler)
-```
-
-Navigate through examples for a better understanding.
-
-- [Overview](routing/overview/main.go)
-- [Basic](routing/basic/main.go)
-- [Controllers](mvc)
-- [Custom HTTP Errors](routing/http-errors/main.go)
-- [Not Found - Suggest Closest Paths](routing/not-found-suggests/main.go) **NEW**
-- [Dynamic Path](routing/dynamic-path/main.go)
- * [root level wildcard path](routing/dynamic-path/root-wildcard/main.go)
-- [Write your own custom parameter types](routing/macros/main.go)
-- [Reverse routing](routing/reverse/main.go)
-- [Custom Router (high-level)](routing/custom-high-level-router/main.go)
-- [Custom Wrapper](routing/custom-wrapper/main.go)
-- Custom Context
- * [method overriding](routing/custom-context/method-overriding/main.go)
- * [new implementation](routing/custom-context/new-implementation/main.go)
-- [Route State](routing/route-state/main.go)
-- [Writing a middleware](routing/writing-a-middleware)
- * [per-route](routing/writing-a-middleware/per-route/main.go)
- * [globally](routing/writing-a-middleware/globally/main.go)
-- [Route Register Rule](routing/route-register-rule/main.go) **NEW**
-
-### Versioning
-
-- [How it works](https://github.com/kataras/iris/blob/master/versioning/README.md)
-- [Example](versioning/main.go)
-
-### Dependency Injection
-
-- [Basic](hero/basic/main.go)
-- [Overview](hero/overview)
-- [Sessions](hero/sessions)
-- [Yet another dependency injection example and good practises at general](hero/smart-contract/main.go)
-
-### MVC
-
-- [Hello world](mvc/hello-world/main.go)
-- [Basic](mvc/basic/main.go)
-- [Basic: wildcard](mvc/basic/wildcard/main.go) **NEW**
-- [Regexp](mvc/regexp/main.go)
-- [Session Controller](mvc/session-controller/main.go)
-- [Overview - Plus Repository and Service layers](mvc/overview)
-- [Login showcase - Plus Repository and Service layers](mvc/login)
-- [Singleton](mvc/singleton)
-- [Websocket Controller](mvc/websocket)
-- [Register Middleware](mvc/middleware)
-- [Vue.js Todo MVC](tutorial/vuejs-todo-mvc)
-- [gRPC-compatible controller](mvc/grpc-compatible/main.go) **NEW**
-
-### Subdomains
-
-- [Single](subdomains/single/main.go)
-- [Multi](subdomains/multi/main.go)
-- [Wildcard](subdomains/wildcard/main.go)
-- [WWW](subdomains/www/main.go)
-- [Redirect fast](subdomains/redirect/main.go)
-
-### Convert `http.Handler/HandlerFunc`
-
-- [From func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)](convert-handlers/negroni-like/main.go)
-- [From http.Handler or http.HandlerFunc](convert-handlers/nethttp/main.go)
-- [From func(http.HandlerFunc) http.HandlerFunc](convert-handlers/real-usecase-raven/writing-middleware/main.go)
-
-### View
-
-- [Overview](view/overview/main.go)
-- [Hi](view/template_html_0/main.go)
-- [A simple Layout](view/template_html_1/main.go)
-- [Layouts: `yield` and `render` tmpl funcs](view/template_html_2/main.go)
-- [The `urlpath` tmpl func](view/template_html_3/main.go)
-- [The `url` tmpl func](view/template_html_4/main.go)
-- [Inject Data Between Handlers](view/context-view-data/main.go)
-- [Embedding Templates Into App Executable File](view/embedding-templates-into-app/main.go)
-- [Write to a custom `io.Writer`](view/write-to)
-- [Greeting with Pug (Jade)`](view/template_pug_0)
-- [Pug (Jade) Actions`](view/template_pug_1)
-- [Pug (Jade) Includes`](view/template_pug_2)
-- [Pug (Jade) Extends`](view/template_pug_3)
-- [Jet](/view/template_jet_0)
-- [Jet Embedded](view/template_jet_1_embedded)
-- [Jet 'urlpath' tmpl func](/view/template_jet_2)
-- [Jet template funcs from structure](/view/template_jet_3)
-
-You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [hero templates](https://github.com/shiyanhui/hero/hero) files too, simply by using the `context#ResponseWriter`, take a look at the [http_responsewriter/quicktemplate](http_responsewriter/quicktemplate) and [http_responsewriter/herotemplate](http_responsewriter/herotemplate) examples.
-
-### Localization and Internationalization
-
-- [I18n](i18n/main.go) **NEW**
-
-### Sitemap
-
-- [Sitemap](sitemap/main.go) **NEW**
-
-### Desktop App
-
-- [Using blink package](desktop-app/blink) **NEW**
-- [Using lorca package](desktop-app/lorca) **NEW**
-- [Using webview package](desktop-app/webview) **NEW**
-
-### Authentication
-
-- [Basic Authentication](authentication/basicauth/main.go)
-- [OAUth2](authentication/oauth2/main.go)
-- [Request Auth(JWT)](experimental-handlers/jwt/main.go)
-- [Sessions](#sessions)
-
-### File Server
-
-- [Favicon](file-server/favicon/main.go)
-- [Basic](file-server/basic/main.go)
-- [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go)
-- [Embedding Gziped Files Into App Executable File](file-server/embedding-gziped-files-into-app/main.go)
-- [Send/Force-Download Files](file-server/send-files/main.go) **UPDATED**
-- Single Page Applications
- * [single Page Application](file-server/single-page-application/basic/main.go)
- * [embedded Single Page Application](file-server/single-page-application/embedded-single-page-application/main.go)
- * [embedded Single Page Application with other routes](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go)
-
-### How to Read from `context.Request() *http.Request`
-
-- [Read JSON](http_request/read-json/main.go)
- * [Struct Validation](http_request/read-json-struct-validation/main.go) **UPDATED**
-- [Read XML](http_request/read-xml/main.go)
-- [Read MsgPack](http_request/read-msgpack/main.go) **NEW**
-- [Read YAML](http_request/read-yaml/main.go)
-- [Read Form](http_request/read-form/main.go)
-- [Read Query](http_request/read-query/main.go)
-- [Read Body](http_request/read-body/main.go) **NEW**
-- [Read Custom per type](http_request/read-custom-per-type/main.go)
-- [Read Custom via Unmarshaler](http_request/read-custom-via-unmarshaler/main.go)
-- [Read Many times](http_request/read-many/main.go)
-- [Upload/Read File](http_request/upload-file/main.go)
-- [Upload multiple files with an easy way](http_request/upload-files/main.go)
-- [Extract referrer from "referer" header or URL query parameter](http_request/extract-referer/main.go)
-
-> The `context.Request()` returns the same *http.Request you already know, these examples show some places where the Context uses this object. Besides that you can use it as you did before iris.
-
-### How to Write to `context.ResponseWriter() http.ResponseWriter`
-
-- [Content Negotiation](http_responsewriter/content-negotiation)
-- [Write `valyala/quicktemplate` templates](http_responsewriter/quicktemplate)
-- [Write `shiyanhui/hero` templates](http_responsewriter/herotemplate)
-- [Text, Markdown, HTML, JSON, JSONP, XML, Binary](http_responsewriter/write-rest/main.go)
-- [Write Gzip](http_responsewriter/write-gzip/main.go)
-- [Stream Writer](http_responsewriter/stream-writer/main.go)
-- [Transactions](http_responsewriter/transactions/main.go)
-- [SSE](http_responsewriter/sse/main.go)
-- [SSE (third-party package usage for server sent events)](http_responsewriter/sse-third-party/main.go)
-
-> The `context/context#ResponseWriter()` returns an enchament version of a http.ResponseWriter, these examples show some places where the Context uses this object. Besides that you can use it as you did before iris.
-
-### ORM
-
-- [Using xorm(Mysql, MyMysql, Postgres, Tidb, **SQLite**, MsSql, MsSql, Oracle)](orm/xorm/main.go)
-- [Using gorm](orm/gorm/main.go)
-
-### Permissions
-
-- [permissions](permissions/main.go) **NEW**
-
-### Miscellaneous
-
-- [Rate Limit](miscellaneous/ratelimit/main.go) **NEW**
-- [HTTP Method Override](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go)
-- [Request Logger](http_request/request-logger/main.go)
- * [log requests to a file](http_request/request-logger/request-logger-file/main.go)
-- [Recovery](miscellaneous/recover/main.go)
-- [Profiling (pprof)](miscellaneous/pprof/main.go)
-- [Internal Application File Logger](miscellaneous/file-logger/main.go)
-- [Google reCAPTCHA](miscellaneous/recaptcha/main.go)
-- [hCaptcha](miscellaneous/hcaptcha/main.go) **NEW**
-
-### Community-based Handlers
-
-- [Casbin wrapper](experimental-handlers/casbin/wrapper/main.go)
-- [Casbin middleware](experimental-handlers/casbin/middleware/main.go)
-- [Cloudwatch](experimental-handlers/cloudwatch/simple/main.go)
-- [CORS](experimental-handlers/cors/simple/main.go)
-- [JWT](experimental-handlers/jwt/main.go)
-- [Newrelic](experimental-handlers/newrelic/simple/main.go)
-- [Prometheus](experimental-handlers/prometheus/simple/main.go)
-- [Secure](experimental-handlers/secure/simple/main.go)
-- [Tollboothic](experimental-handlers/tollboothic/limit-handler/main.go)
-- [Cross-Site Request Forgery Protection](experimental-handlers/csrf/main.go)
-
-#### More
-
-https://github.com/kataras/iris/tree/master/middleware#third-party-handlers
-
-### Automated API Documentation
-
-- [yaag](apidoc/yaag/main.go)
-
-### Testing
-
-The `httptest` package is your way for end-to-end HTTP testing, it uses the httpexpect library created by our friend, [gavv](https://github.com/gavv).
-
-[Example](testing/httptest/main_test.go)
-
-### Caching
-
-iris cache library lives on its own [package](https://github.com/kataras/iris/tree/master/cache).
-
-- [Simple](cache/simple/main.go)
-- [Client-Side (304)](cache/client-side/main.go) - part of the iris context core
-
-> You're free to use your own favourite caching package if you'd like so.
-
-### Cookies
-
-- [Basic](cookies/basic/main.go)
-- [Encode/Decode (securecookie)](cookies/securecookie/main.go)
-
-### Sessions
-
-iris session manager lives on its own [package](https://github.com/kataras/iris/tree/master/sessions).
-
-- [Overview](sessions/overview/main.go)
-- [Middleware](sessions/middleware/main.go)
-- [Secure Cookie](sessions/securecookie/main.go)
-- [Flash Messages](sessions/flash-messages/main.go)
-- [Databases](sessions/database)
- * [Badger](sessions/database/badger/main.go)
- * [BoltDB](sessions/database/boltdb/main.go)
- * [Redis](sessions/database/redis/main.go)
-
-> You're free to use your own favourite sessions package if you'd like so.
-
-### Websockets
-
-- [Basic](websocket/basic)
- * [Server](websocket/basic/server.go)
- * [Go Client](websocket/basic/go-client/client.go)
- * [Browser Client](websocket/basic/browser/index.html)
- * [Browser NPM Client (browserify)](websocket/basic/browserify/app.js)
-- [Native Messages](websocket/native-messages/main.go)
-- [TLS Enabled](websocket/secure/README.md)
-
-### Hey, You
-
-Developers should read the [godocs](https://godoc.org/github.com/kataras/iris) and https://docs.iris-go.com for a better understanding.
-
-Psst, I almost forgot; do not forget to [star or watch](https://github.com/kataras/iris/stargazers) the project in order to stay updated with the latest tech trends, it never takes more than a second!
+# Table of Contents
+
+* Tutorials
+ * [Caddy](tutorial/caddy)
+ * [MongoDB](tutorial/mongodb)
+ * [Dropzone.js](tutorial/dropzonejs)
+ * [URL Shortener](tutorial/url-shortener/main.go)
+ * [Online Visitors](tutorial/online-visitors/main.go)
+ * [REST API for Apache Kafka](tutorial/api-for-apache-kafka)
+ * [Vue.js Todo (MVC)](tutorial/vuejs-todo-mvc)
+ * [gRPC (MVC)](mvc/grpc-compatible)
+* HTTP Listening
+ * [HOST:PORT](http-listening/listen-addr/main.go)
+ * [Public Test Domain](http-listening/listen-addr-public/main.go)
+ * [UNIX socket file](http-listening/listen-unix/main.go)
+ * [TLS](http-listening/listen-tls/main.go)
+ * [Letsencrypt (Automatic Certifications)](http-listening/listen-letsencrypt/main.go)
+ * [Graceful Shutdown](http-listening/graceful-shutdown/default-notifier/main.go)
+ * [Notify on shutdown](http-listening/notify-on-shutdown/main.go)
+ * Custom TCP Listener
+ * [Common net.Listener](http-listening/custom-listener/main.go)
+ * [SO_REUSEPORT for unix systems](http-listening/custom-listener/unix-reuseport/main.go)
+ * Custom HTTP Server
+ * [Pass a custom Server](http-listening/custom-httpserver/easy-way/main.go)
+ * [Use Iris as a single http.Handler](http-listening/custom-httpserver/std-way/main.go)
+ * [Multi Instances](http-listening/custom-httpserver/multi/main.go)
+ * [HTTP/3 Quic](http-listening/http3-quic)
+* Configuration
+ * [Functional](configuration/functional/main.go)
+ * [Configuration Struct](configuration/from-configuration-structure/main.go)
+ * [Import from YAML](configuration/from-yaml-file/main.go)
+ * [Share Configuration across instances](configuration/from-yaml-file/shared-configuration/main.go)
+ * [Import from TOML](configuration/from-toml-file/main.go)
+* Routing
+ * [Overview](routing/overview/main.go)
+ * [Basic](routing/basic/main.go)
+ * [Custom HTTP Errors](routing/http-errors/main.go)
+ * [Not Found - Suggest Closest Paths](routing/not-found-suggests/main.go)
+ * [Dynamic Path](routing/dynamic-path/main.go)
+ * [Root Wildcard](routing/dynamic-path/root-wildcard/main.go)
+ * [Implement a Parameter Type](routing/macros/main.go)
+ * Middleware
+ * [Per Route](routing/writing-a-middleware/per-route/main.go)
+ * [Globally](routing/writing-a-middleware/globally/main.go)
+ * [Route Register Rule](routing/route-register-rule/main.go)
+ * Convert net/http Handlers
+ * [From func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)](convert-handlers/negroni-like/main.go)
+ * [From http.Handler or http.HandlerFunc](convert-handlers/nethttp/main.go)
+ * [From func(http.HandlerFunc) http.HandlerFunc](convert-handlers/real-usecase-raven/writing-middleware/main.go)
+ * [Route State](routing/route-state/main.go)
+ * [Reverse Routing](routing/reverse/main.go)
+ * [Router Wrapper](routing/custom-wrapper/main.go)
+ * [Custom Router](routing/custom-high-level-router/main.go)
+ * Custom Context
+ * [Method Overriding](routing/custom-context/method-overriding/main.go)
+ * [New Implementation](routing/custom-context/new-implementation/main.go)
+* Subdomains
+ * [Single](subdomains/single/main.go)
+ * [Multi](subdomains/multi/main.go)
+ * [Wildcard](subdomains/wildcard/main.go)
+ * [WWW](subdomains/www/main.go)
+ * [Redirection](subdomains/redirect/main.go)
+* API Versioning
+ * [How it works](https://github.com/kataras/iris/wiki/API-versioning)
+ * [Example](versioning/main.go)
+* API Documentation
+ * [yaag](apidoc/yaag/main.go)
+* Testing
+ * [Example](testing/httptest/main_test.go)
+* File Server
+ * [Favicon](file-server/favicon/main.go)
+ * [Basic](file-server/basic/main.go)
+ * [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go)
+ * [Embedding Gziped Files Into App Executable File](file-server/embedding-gziped-files-into-app/main.go)
+ * [Send Files (rate limiter included)](file-server/send-files/main.go)
+ * Single Page Applications
+ * [Basic SPA](file-server/single-page-application/basic/main.go)
+ * [Embedded Single Page Application](file-server/single-page-application/embedded-single-page-application/main.go)
+ * [Embedded Single Page Application with other routes](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go)
+* View
+ * [Overview](view/overview/main.go)
+ * [Hi](view/template_html_0/main.go)
+ * [A simple Layout](view/template_html_1/main.go)
+ * [Layouts: `yield` and `render` tmpl funcs](view/template_html_2/main.go)
+ * [The `urlpath` tmpl func](view/template_html_3/main.go)
+ * [The `url` tmpl func](view/template_html_4/main.go)
+ * [Inject Data Between Handlers](view/context-view-data/main.go)
+ * [Embedding Templates Into App Executable File](view/embedding-templates-into-app/main.go)
+ * [Write to a custom `io.Writer`](view/write-to)
+ * [Greeting with Pug (Jade)`](view/template_pug_0)
+ * [Pug (Jade) Actions`](view/template_pug_1)
+ * [Pug (Jade) Includes`](view/template_pug_2)
+ * [Pug (Jade) Extends`](view/template_pug_3)
+ * [Jet](/view/template_jet_0)
+ * [Jet Embedded](view/template_jet_1_embedded)
+ * [Jet 'urlpath' tmpl func](/view/template_jet_2)
+ * [Jet template funcs from structure](/view/template_jet_3)
+ * Third-Parties
+ * [Render `valyala/quicktemplate` templates](http_responsewriter/quicktemplate)
+ * [Render `shiyanhui/hero` templates](http_responsewriter/herotemplate)
+* Request Body
+ * [Bind JSON](http_request/read-json/main.go)
+ * * [Struct Validation](http_request/read-json-struct-validation/main.go)
+ * [Bind XML](http_request/read-xml/main.go)
+ * [Bind MsgPack](http_request/read-msgpack/main.go)
+ * [Bind YAML](http_request/read-yaml/main.go)
+ * [Bind Form](http_request/read-form/main.go)
+ * [Bind Query](http_request/read-query/main.go)
+ * [Bind Body](http_request/read-body/main.go)
+ * [Bind Custom per type](http_request/read-custom-per-type/main.go)
+ * [Bind Custom via Unmarshaler](http_request/read-custom-via-unmarshaler/main.go)
+ * [Bind Many times](http_request/read-many/main.go)
+ * [Upload/Read File](http_request/upload-file/main.go)
+ * [Upload multiple Files](http_request/upload-files/main.go)
+ * [Extract Referrer](http_request/extract-referer/main.go)
+* Response Writer
+ * [Content Negotiation](http_responsewriter/content-negotiation)
+ * [Text, Markdown, YAML, HTML, JSON, JSONP, Msgpack, XML and Binary](http_responsewriter/write-rest/main.go)
+ * [Write Gzip](http_responsewriter/write-gzip/main.go)
+ * [Stream Writer](http_responsewriter/stream-writer/main.go)
+ * [Transactions](http_responsewriter/transactions/main.go)
+ * [SSE](http_responsewriter/sse/main.go)
+ * [SSE (third-party package usage for server sent events)](http_responsewriter/sse-third-party/main.go)
+* Cache
+ * [Simple](cache/simple/main.go)
+ * [Client-Side (304)](cache/client-side/main.go)
+* Localization and Internationalization
+ * [i18n](i18n/main.go)
+* Sitemaps
+ * [Sitemap](sitemap/main.go)
+* Authentication
+ * [Basic Authentication](authentication/basicauth/main.go)
+ * [OAUth2](authentication/oauth2/main.go)
+ * [Request Auth(JWT)](experimental-handlers/jwt/main.go)
+ * [Manage Permissions](permissions/main.go)
+* Cookies
+ * [Basic](cookies/basic/main.go)
+ * [Encode/Decode (with `securecookie`)](cookies/securecookie/main.go)
+* Sessions
+ * [Overview](sessions/overview/main.go)
+ * [Middleware](sessions/middleware/main.go)
+ * [Secure Cookie](sessions/securecookie/main.go)
+ * [Flash Messages](sessions/flash-messages/main.go)
+ * [Databases](sessions/database)
+ * [Badger](sessions/database/badger/main.go)
+ * [BoltDB](sessions/database/boltdb/main.go)
+ * [Redis](sessions/database/redis/main.go)
+* Websocket
+ * [Basic](websocket/basic)
+ * [Server](websocket/basic/server.go)
+ * [Go Client](websocket/basic/go-client/client.go)
+ * [Browser Client](websocket/basic/browser/index.html)
+ * [Browser NPM Client (browserify)](websocket/basic/browserify/app.js)
+ * [Native Messages](websocket/native-messages/main.go)
+ * [TLS](websocket/secure/README.md)
+* Dependency Injection
+ * [Overview (Movies Service)](ependency-injection/overview/main.go)
+ * [Basic](dependency-injection/basic/main.go)
+ * [Middleware](dependency-injection/basic/middleware/main.go)
+ * [Sessions](dependency-injection/sessions/main.go)
+ * [Smart Contract](dependency-injection/smart-contract/main.go)
+* MVC
+ * [Overview - Repository and Service layers](mvc/overview)
+ * [Login - Repository and Service layers](mvc/login)
+ * [Hello world](mvc/hello-world/main.go)
+ * [Basic](mvc/basic/main.go)
+ * [Wildcard](mvc/basic/wildcard/main.go)
+ * [Singleton](mvc/singleton)
+ * [Regexp](mvc/regexp/main.go)
+ * [Session Controller](mvc/session-controller/main.go)
+ * [Websocket Controller](mvc/websocket)
+ * [Register Middleware](mvc/middleware)
+* Object-Relational Mapping
+ * [Using `go-xorm/xorm` (Mysql, MyMysql, Postgres, Tidb, SQLite, MsSql, MsSql, Oracle)](orm/xorm/main.go)
+ * [Using `jinzhu/gorm`](orm/gorm/main.go)
+* Project Structure
+ * [Bootstrapper](structuring/bootstrap)
+ * [MVC with Repository and Service layer Overview](structuring/mvc-plus-repository-and-service-layers)
+ * [Login (MVC with Single Responsibility package)](structuring/login-mvc-single-responsibility-package)
+ * [Login (MVC with Datamodels, Datasource, Repository and Service layer)](structuring/login-mvc)
+* Desktop Applications
+ * [The blink package](desktop-app/blink)
+ * [The lorca package](desktop-app/lorca)
+ * [The webview package](desktop-app/webview)
+* Middlewares (Builtin)
+ * [Rate Limit](miscellaneous/ratelimit/main.go)
+ * [HTTP Method Override](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go)
+ * [Request Logger](http_request/request-logger/main.go)
+ * [Log Requests to a File](http_request/request-logger/request-logger-file/main.go)
+ * [Recovery](miscellaneous/recover/main.go)
+ * [Profiling (pprof)](miscellaneous/pprof/main.go)
+ * [Internal Application File Logger](miscellaneous/file-logger/main.go)
+ * [Google reCAPTCHA](miscellaneous/recaptcha/main.go)
+ * [hCaptcha](miscellaneous/hcaptcha/main.go)
+* Middlewares [(Community)](https://github.com/iris-contrib/middleware)
diff --git a/_examples/configuration/README.md b/_examples/configuration/README.md
deleted file mode 100644
index a018c6f6..00000000
--- a/_examples/configuration/README.md
+++ /dev/null
@@ -1,345 +0,0 @@
-# Configuration
-
-All configuration's values have default values, things will work as you expected with `iris.New()`.
-
-Configuration is useless before listen functions, so it should be passed on `Application#Run/2` (second argument(s)).
-
-Iris has a type named `Configurator` which is a `func(*iris.Application)`, any function
-which completes this can be passed at `Application#Configure` and/or `Application#Run/2`.
-
-`Application#ConfigurationReadOnly()` returns the configuration values.
-
-`.Run` **by `Configuration` struct**
-
-```go
-package main
-
-import (
- "github.com/kataras/iris/v12"
-)
-
-func main() {
- app := iris.New()
- app.Get("/", func(ctx iris.Context) {
- ctx.HTML("Hello!")
- })
- // [...]
-
- // Good when you want to modify the whole configuration.
- app.Listen(":8080", iris.WithConfiguration(iris.Configuration{
- DisableStartupLog: false,
- DisableInterruptHandler: false,
- DisablePathCorrection: false,
- EnablePathEscape: false,
- FireMethodNotAllowed: false,
- DisableBodyConsumptionOnUnmarshal: false,
- DisableAutoFireStatusCode: false,
- TimeFormat: "Mon, 02 Jan 2006 15:04:05 GMT",
- Charset: "utf-8",
- }))
-}
-```
-
-`.Run` **by options**
-
-```go
-package main
-
-import (
- "github.com/kataras/iris/v12"
-)
-
-func main() {
- app := iris.New()
- app.Get("/", func(ctx iris.Context) {
- ctx.HTML("Hello!")
- })
- // [...]
-
- // Good when you want to change some of the configuration's field.
- // Prefix: "With", code editors will help you navigate through all
- // configuration options without even a glitch to the documentation.
-
- app.Listen(":8080", iris.WithoutStartupLog, iris.WithCharset("utf-8"))
-
- // or before run:
- // app.Configure(iris.WithoutStartupLog, iris.WithCharset("utf-8"))
- // app.Listen(":8080")
-}
-```
-
-`.Run` **by TOML config file**
-
-```tml
-DisablePathCorrection = false
-EnablePathEscape = false
-FireMethodNotAllowed = true
-DisableBodyConsumptionOnUnmarshal = false
-TimeFormat = "Mon, 01 Jan 2006 15:04:05 GMT"
-Charset = "utf-8"
-
-[Other]
- MyServerName = "iris"
-
-```
-
-```go
-package main
-
-import (
- "github.com/kataras/iris/v12"
-)
-
-func main() {
- app := iris.New()
-
- app.Get("/", func(ctx iris.Context) {
- ctx.HTML("Hello!")
- })
- // [...]
-
- // Good when you have two configurations, one for development and a different one for production use.
- app.Listen(":8080", iris.WithConfiguration(iris.TOML("./configs/iris.tml")))
-}
-```
-
-
-`.Run` **by YAML config file**
-
-```yml
-DisablePathCorrection: false
-EnablePathEscape: false
-FireMethodNotAllowed: true
-DisableBodyConsumptionOnUnmarshal: true
-TimeFormat: Mon, 01 Jan 2006 15:04:05 GMT
-Charset: UTF-8
-```
-
-```go
-package main
-
-import (
- "github.com/kataras/iris/v12"
-)
-
-func main() {
- app := iris.New()
- app.Get("/", func(ctx iris.Context) {
- ctx.HTML("Hello!")
- })
- // [...]
-
- app.Listen(":8080", iris.WithConfiguration(iris.YAML("./configs/iris.yml")))
-}
-
-```
-
-## Builtin Configurators
-
-```go
-
-// WithGlobalConfiguration will load the global yaml configuration file
-// from the home directory and it will set/override the whole app's configuration
-// to that file's contents. The global configuration file can be modified by user
-// and be used by multiple iris instances.
-//
-// This is useful when we run multiple iris servers that share the same
-// configuration, even with custom values at its "Other" field.
-//
-// Usage: `app.Configure(iris.WithGlobalConfiguration)` or `app.Run([iris.Runner], iris.WithGlobalConfiguration)`.
-WithGlobalConfiguration
-
-// variables for configurators don't need any receivers, functions
-// for them that need (helps code editors to recognise as variables without parenthesis completion).
-
-// WithoutServerError will cause to ignore the matched "errors"
-// from the main application's `Run` function.
-//
-// Usage:
-// err := app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
-// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
-//
-// See `Configuration#IgnoreServerErrors []string` too.
-//
-// Example: https://github.com/kataras/iris/tree/master/_examples/http-listening/listen-addr/omit-server-errors
-WithoutServerError(errors ...error) Configurator
-
-// WithoutStartupLog turns off the information send, once, to the terminal when the main server is open.
-WithoutStartupLog
-
-// WithoutInterruptHandler disables the automatic graceful server shutdown
-// when control/cmd+C pressed.
-WithoutInterruptHandle
-
-// WithoutPathCorrection disables the PathCorrection setting.
-//
-// See `Configuration`.
-WithoutPathCorrectio
-
-// WithoutPathCorrectionRedirection disables the PathCorrectionRedirection setting.
-//
-// See `Configuration`.
-WithoutPathCorrectionRedirection
-
-// WithoutBodyConsumptionOnUnmarshal disables BodyConsumptionOnUnmarshal setting.
-//
-// See `Configuration`.
-WithoutBodyConsumptionOnUnmarshal
-
-// WithoutAutoFireStatusCode disables the AutoFireStatusCode setting.
-//
-// See `Configuration`.
-WithoutAutoFireStatusCode
-
-// WithPathEscape enables the PathEscape setting.
-//
-// See `Configuration`.
-WithPathEscape
-
-// WithOptimizations can force the application to optimize for the best performance where is possible.
-//
-// See `Configuration`.
-WithOptimizations
-
-// WithFireMethodNotAllowed enables the FireMethodNotAllowed setting.
-//
-// See `Configuration`.
-WithFireMethodNotAllowed
-
-// WithTimeFormat sets the TimeFormat setting.
-//
-// See `Configuration`.
-WithTimeFormat(timeformat string) Configurator
-
-// WithCharset sets the Charset setting.
-//
-// See `Configuration`.
-WithCharset(charset string) Configurator
-
-// 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.
-WithPostMaxMemory(limit int64) Configurator
-
-// WithRemoteAddrHeader enables or adds a new or existing request header name
-// that can be used to validate the client's real IP.
-//
-// By-default no "X-" header is consired safe to be used for retrieving the
-// client's IP address, because those headers can manually change by
-// the client. But sometimes are useful e.g., when behind a proxy
-// you want to enable the "X-Forwarded-For" or when cloudflare
-// you want to enable the "CF-Connecting-IP", inneed you
-// can allow the `ctx.RemoteAddr()` to use any header
-// that the client may sent.
-//
-// Defaults to an empty map but an example usage is:
-// WithRemoteAddrHeader("X-Forwarded-For")
-//
-// Look `context.RemoteAddr()` for more.
-WithRemoteAddrHeader(headerName string) Configurator
-
-// WithoutRemoteAddrHeader disables an existing request header name
-// that can be used to validate and parse the client's real IP.
-//
-//
-// Keep note that RemoteAddrHeaders is already defaults to an empty map
-// so you don't have to call this Configurator if you didn't
-// add allowed headers via configuration or via `WithRemoteAddrHeader` before.
-//
-// Look `context.RemoteAddr()` for more.
-WithoutRemoteAddrHeader(headerName string) Configurator
-
-// WithRemoteAddrPrivateSubnet adds a new private sub-net to be excluded from `context.RemoteAddr`.
-// See `WithRemoteAddrHeader` too.
-WithRemoteAddrPrivateSubnet(startIP, endIP string) Configurator
-
-// WithOtherValue adds a value based on a key to the Other setting.
-//
-// See `Configuration.Other`.
-WithOtherValue(key string, val interface{}) Configurator
-
-// WithSitemap enables the sitemap generator.
-// Use the Route's `SetLastMod`, `SetChangeFreq` and `SetPriority` to modify
-// the sitemap's URL child element properties.
-//
-// It accepts a "startURL" input argument which
-// is the prefix for the registered routes that will be included in the sitemap.
-//
-// If more than 50,000 static routes are registered then sitemaps will be splitted and a sitemap index will be served in
-// /sitemap.xml.
-//
-// If `Application.I18n.Load/LoadAssets` is called then the sitemap will contain translated links for each static route.
-//
-// If the result does not complete your needs you can take control
-// and use the github.com/kataras/sitemap package to generate a customized one instead.
-//
-// Example: https://github.com/kataras/iris/tree/master/_examples/sitemap.
-WithSitemap(startURL string) Configurator
-
-// WithTunneling is the `iris.Configurator` for the `iris.Configuration.Tunneling` field.
-// It's used to enable http tunneling for an Iris Application, per registered host
-//
-// Alternatively use the `iris.WithConfiguration(iris.Configuration{Tunneling: iris.TunnelingConfiguration{ ...}}}`.
-WithTunneling
-```
-
-## Custom Configurator
-
-With the `Configurator` developers can modularize their applications with ease.
-
-Example Code:
-
-```go
-// file counter/counter.go
-package counter
-
-import (
- "time"
-
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/core/host"
-)
-
-func Configurator(app *iris.Application) {
- counterValue := 0
-
- go func() {
- ticker := time.NewTicker(time.Second)
-
- for range ticker.C {
- counterValue++
- }
-
- app.ConfigureHost(func(h *host.Supervisor) { // <- HERE: IMPORTANT
- h.RegisterOnShutdown(func() {
- ticker.Stop()
- })
- })
- }()
-
- app.Get("/counter", func(ctx iris.Context) {
- ctx.Writef("Counter value = %d", counterValue)
- })
-}
-```
-
-```go
-// file: main.go
-package main
-
-import (
- "counter"
-
- "github.com/kataras/iris/v12"
-)
-
-func main() {
- app := iris.New()
- app.Configure(counter.Configurator)
-
- app.Listen(":8080")
-}
-```
\ No newline at end of file
diff --git a/_examples/hero/overview/datamodels/movie.go b/_examples/dependency-injection/overview/datamodels/movie.go
similarity index 95%
rename from _examples/hero/overview/datamodels/movie.go
rename to _examples/dependency-injection/overview/datamodels/movie.go
index 7649d487..9797b538 100644
--- a/_examples/hero/overview/datamodels/movie.go
+++ b/_examples/dependency-injection/overview/datamodels/movie.go
@@ -10,7 +10,7 @@ package datamodels
// as the only one Movie model in our application,
// for the shake of simplicty.
type Movie struct {
- ID int64 `json:"id"`
+ ID uint64 `json:"id"`
Name string `json:"name"`
Year int `json:"year"`
Genre string `json:"genre"`
diff --git a/_examples/hero/overview/datasource/movies.go b/_examples/dependency-injection/overview/datasource/movies.go
similarity index 86%
rename from _examples/hero/overview/datasource/movies.go
rename to _examples/dependency-injection/overview/datasource/movies.go
index ee07c357..4b5fbf31 100644
--- a/_examples/hero/overview/datasource/movies.go
+++ b/_examples/dependency-injection/overview/datasource/movies.go
@@ -2,10 +2,10 @@
package datasource
-import "github.com/kataras/iris/v12/_examples/hero/overview/datamodels"
+import "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels"
// Movies is our imaginary data source.
-var Movies = map[int64]datamodels.Movie{
+var Movies = map[uint64]datamodels.Movie{
1: {
ID: 1,
Name: "Casablanca",
diff --git a/_examples/dependency-injection/overview/main.go b/_examples/dependency-injection/overview/main.go
new file mode 100644
index 00000000..8386aaae
--- /dev/null
+++ b/_examples/dependency-injection/overview/main.go
@@ -0,0 +1,55 @@
+// file: main.go
+
+package main
+
+import (
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datasource"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/repositories"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/services"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/web/middleware"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/web/routes"
+
+ "github.com/kataras/iris/v12"
+)
+
+func main() {
+ app := iris.New()
+ app.Logger().SetLevel("debug")
+
+ // Load the template files.
+ app.RegisterView(iris.HTML("./web/views", ".html"))
+
+ // Create our movie repository with some (memory) data from the datasource.
+ repo := repositories.NewMovieRepository(datasource.Movies)
+
+ app.Party("/hello").ConfigureContainer(func(r *iris.APIContainer) {
+ r.Get("/", routes.Hello)
+ r.Get("/{name}", routes.HelloName)
+ })
+
+ app.Party("/movies").ConfigureContainer(func(r *iris.APIContainer) {
+ // Create our movie service, we will bind it to the movie app's dependencies.
+ movieService := services.NewMovieService(repo)
+ r.RegisterDependency(movieService)
+
+ // Add the basic authentication(admin:password) middleware
+ // for the /movies based requests.
+ r.Use(middleware.BasicAuth)
+
+ r.Get("/", routes.Movies)
+ r.Get("/{id:uint64}", routes.MovieByID)
+ r.Put("/{id:uint64}", routes.UpdateMovieByID)
+ r.Delete("/{id:uint64}", routes.DeleteMovieByID)
+ })
+
+ // http://localhost:8080/hello
+ // http://localhost:8080/hello/iris
+ // http://localhost:8080/movies ("admin": "password")
+ // http://localhost:8080/movies/1
+ app.Listen(
+ // Start the web server at localhost:8080
+ "localhost:8080",
+ // enables faster json serialization and more:
+ iris.WithOptimizations,
+ )
+}
diff --git a/_examples/hero/overview/repositories/movie_repository.go b/_examples/dependency-injection/overview/repositories/movie_repository.go
similarity index 95%
rename from _examples/hero/overview/repositories/movie_repository.go
rename to _examples/dependency-injection/overview/repositories/movie_repository.go
index 491d1785..0a46cb1b 100644
--- a/_examples/hero/overview/repositories/movie_repository.go
+++ b/_examples/dependency-injection/overview/repositories/movie_repository.go
@@ -6,7 +6,7 @@ import (
"errors"
"sync"
- "github.com/kataras/iris/v12/_examples/hero/overview/datamodels"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels"
)
// Query represents the visitor and action queries.
@@ -27,14 +27,14 @@ type MovieRepository interface {
// NewMovieRepository returns a new movie memory-based repository,
// the one and only repository type in our example.
-func NewMovieRepository(source map[int64]datamodels.Movie) MovieRepository {
+func NewMovieRepository(source map[uint64]datamodels.Movie) MovieRepository {
return &movieMemoryRepository{source: source}
}
// movieMemoryRepository is a "MovieRepository"
// which manages the movies using the memory data source (map).
type movieMemoryRepository struct {
- source map[int64]datamodels.Movie
+ source map[uint64]datamodels.Movie
mu sync.RWMutex
}
@@ -115,7 +115,7 @@ func (r *movieMemoryRepository) InsertOrUpdate(movie datamodels.Movie) (datamode
id := movie.ID
if id == 0 { // Create new action
- var lastID int64
+ var lastID uint64
// find the biggest ID in order to not have duplications
// in productions apps you can use a third-party
// library to generate a UUID as string.
diff --git a/_examples/hero/overview/services/movie_service.go b/_examples/dependency-injection/overview/services/movie_service.go
similarity index 72%
rename from _examples/hero/overview/services/movie_service.go
rename to _examples/dependency-injection/overview/services/movie_service.go
index 109e88d9..6835a9b5 100644
--- a/_examples/hero/overview/services/movie_service.go
+++ b/_examples/dependency-injection/overview/services/movie_service.go
@@ -3,8 +3,8 @@
package services
import (
- "github.com/kataras/iris/v12/_examples/hero/overview/datamodels"
- "github.com/kataras/iris/v12/_examples/hero/overview/repositories"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/repositories"
)
// MovieService handles some of the CRUID operations of the movie datamodel.
@@ -15,9 +15,9 @@ import (
// because we may need to change or try an experimental different domain logic at the future.
type MovieService interface {
GetAll() []datamodels.Movie
- GetByID(id int64) (datamodels.Movie, bool)
- DeleteByID(id int64) bool
- UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error)
+ GetByID(id uint64) (datamodels.Movie, bool)
+ DeleteByID(id uint64) bool
+ UpdatePosterAndGenreByID(id uint64, poster string, genre string) (datamodels.Movie, error)
}
// NewMovieService returns the default movie service.
@@ -39,14 +39,14 @@ func (s *movieService) GetAll() []datamodels.Movie {
}
// GetByID returns a movie based on its id.
-func (s *movieService) GetByID(id int64) (datamodels.Movie, bool) {
+func (s *movieService) GetByID(id uint64) (datamodels.Movie, bool) {
return s.repo.Select(func(m datamodels.Movie) bool {
return m.ID == id
})
}
// UpdatePosterAndGenreByID updates a movie's poster and genre.
-func (s *movieService) UpdatePosterAndGenreByID(id int64, poster string, genre string) (datamodels.Movie, error) {
+func (s *movieService) UpdatePosterAndGenreByID(id uint64, poster string, genre string) (datamodels.Movie, error) {
// update the movie and return it.
return s.repo.InsertOrUpdate(datamodels.Movie{
ID: id,
@@ -58,7 +58,7 @@ func (s *movieService) UpdatePosterAndGenreByID(id int64, poster string, genre s
// DeleteByID deletes a movie by its id.
//
// Returns true if deleted otherwise false.
-func (s *movieService) DeleteByID(id int64) bool {
+func (s *movieService) DeleteByID(id uint64) bool {
return s.repo.Delete(func(m datamodels.Movie) bool {
return m.ID == id
}, 1)
diff --git a/_examples/hero/overview/web/middleware/basicauth.go b/_examples/dependency-injection/overview/web/middleware/basicauth.go
similarity index 100%
rename from _examples/hero/overview/web/middleware/basicauth.go
rename to _examples/dependency-injection/overview/web/middleware/basicauth.go
diff --git a/_examples/hero/overview/web/routes/hello.go b/_examples/dependency-injection/overview/web/routes/hello.go
similarity index 100%
rename from _examples/hero/overview/web/routes/hello.go
rename to _examples/dependency-injection/overview/web/routes/hello.go
diff --git a/_examples/hero/overview/web/routes/movies.go b/_examples/dependency-injection/overview/web/routes/movies.go
similarity index 79%
rename from _examples/hero/overview/web/routes/movies.go
rename to _examples/dependency-injection/overview/web/routes/movies.go
index 9b6af164..d6b902d9 100644
--- a/_examples/hero/overview/web/routes/movies.go
+++ b/_examples/dependency-injection/overview/web/routes/movies.go
@@ -5,8 +5,8 @@ package routes
import (
"errors"
- "github.com/kataras/iris/v12/_examples/hero/overview/datamodels"
- "github.com/kataras/iris/v12/_examples/hero/overview/services"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/datamodels"
+ "github.com/kataras/iris/v12/_examples/dependency-injection/overview/services"
"github.com/kataras/iris/v12"
)
@@ -21,14 +21,14 @@ func Movies(service services.MovieService) (results []datamodels.Movie) {
// MovieByID returns a movie.
// Demo:
// curl -i http://localhost:8080/movies/1
-func MovieByID(service services.MovieService, id int64) (movie datamodels.Movie, found bool) {
+func MovieByID(service services.MovieService, id uint64) (movie datamodels.Movie, found bool) {
return service.GetByID(id) // it will throw 404 if not found.
}
// UpdateMovieByID updates a movie.
// Demo:
// curl -i -X PUT -F "genre=Thriller" -F "poster=@/Users/kataras/Downloads/out.gif" http://localhost:8080/movies/1
-func UpdateMovieByID(ctx iris.Context, service services.MovieService, id int64) (datamodels.Movie, error) {
+func UpdateMovieByID(ctx iris.Context, service services.MovieService, id uint64) (datamodels.Movie, error) {
// get the request data for poster and genre
file, info, err := ctx.FormFile("poster")
if err != nil {
@@ -47,7 +47,7 @@ func UpdateMovieByID(ctx iris.Context, service services.MovieService, id int64)
// DeleteMovieByID deletes a movie.
// Demo:
// curl -i -X DELETE -u admin:password http://localhost:8080/movies/1
-func DeleteMovieByID(service services.MovieService, id int64) interface{} {
+func DeleteMovieByID(service services.MovieService, id uint64) interface{} {
wasDel := service.DeleteByID(id)
if wasDel {
// return the deleted movie's ID
diff --git a/_examples/hero/overview/web/views/hello/index.html b/_examples/dependency-injection/overview/web/views/hello/index.html
similarity index 100%
rename from _examples/hero/overview/web/views/hello/index.html
rename to _examples/dependency-injection/overview/web/views/hello/index.html
diff --git a/_examples/hero/overview/web/views/hello/name.html b/_examples/dependency-injection/overview/web/views/hello/name.html
similarity index 100%
rename from _examples/hero/overview/web/views/hello/name.html
rename to _examples/dependency-injection/overview/web/views/hello/name.html
diff --git a/_examples/dependency-injection/sessions/main.go b/_examples/dependency-injection/sessions/main.go
new file mode 100644
index 00000000..2172c34c
--- /dev/null
+++ b/_examples/dependency-injection/sessions/main.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+ "time"
+
+ "github.com/kataras/iris/v12/_examples/dependency-injection/sessions/routes"
+
+ "github.com/kataras/iris/v12"
+ "github.com/kataras/iris/v12/sessions"
+)
+
+func main() {
+ app := iris.New()
+ sessionManager := sessions.New(sessions.Config{
+ Cookie: "site_session_id",
+ Expires: 60 * time.Minute,
+ AllowReclaim: true,
+ })
+
+ // Session is automatically binded through `sessions.Get(ctx)`
+ // if a *sessions.Session input argument is present on the handler's function,
+ // which `routes.Index` does.
+ app.Use(sessionManager.Handler())
+
+ // Method: GET
+ // Path: http://localhost:8080
+ app.ConfigureContainer(registerRoutes)
+
+ app.Listen(":8080")
+}
+
+func registerRoutes(api *iris.APIContainer) {
+ api.Get("/", routes.Index)
+}
diff --git a/_examples/dependency-injection/sessions/routes/index.go b/_examples/dependency-injection/sessions/routes/index.go
new file mode 100644
index 00000000..d1660563
--- /dev/null
+++ b/_examples/dependency-injection/sessions/routes/index.go
@@ -0,0 +1,17 @@
+package routes
+
+import (
+ "fmt"
+
+ "github.com/kataras/iris/v12/sessions"
+)
+
+// Index will increment a simple int version based on the visits that this user/session did.
+func Index(session *sessions.Session) string {
+ // it increments a "visits" value of integer by one,
+ // if the entry with key 'visits' doesn't exist it will create it for you.
+ visits := session.Increment("visits", 1)
+
+ // write the current, updated visits.
+ return fmt.Sprintf("%d visit(s) from my current session", visits)
+}
diff --git a/_examples/hero/smart-contract/main.go b/_examples/dependency-injection/smart-contract/main.go
similarity index 81%
rename from _examples/hero/smart-contract/main.go
rename to _examples/dependency-injection/smart-contract/main.go
index fd635309..f3c93f33 100644
--- a/_examples/hero/smart-contract/main.go
+++ b/_examples/dependency-injection/smart-contract/main.go
@@ -5,8 +5,6 @@ import (
"strings"
"github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/context"
- "github.com/kataras/iris/v12/hero"
// External package to optionally filter JSON responses before sent,
// see `sendJSON` for more.
@@ -17,19 +15,9 @@ import (
$ go get github.com/jmespath/go-jmespath
*/
-func newApp() *iris.Application {
- app := iris.New()
-
- // PartyFunc is the same as usersRouter := app.Party("/users")
- // but it gives us an easy way to call router's registration functions,
- // i.e functions from another package that can handle this group of routes.
- app.PartyFunc("/users", registerUsersRoutes)
-
- return app
-}
-
func main() {
app := newApp()
+ app.Logger().SetLevel("debug")
// http://localhost:8080/users?query=[?Name == 'John Doe'].Age
// <- client will receive the age of a user which his name is "John Doe".
@@ -45,6 +33,17 @@ func main() {
app.Listen(":8080")
}
+func newApp() *iris.Application {
+ app := iris.New()
+
+ // PartyFunc is the same as usersRouter := app.Party("/users")
+ // but it gives us an easy way to call router's registration functions,
+ // i.e functions from another package that can handle this group of routes.
+ app.PartyFunc("/users", registerUsersRoutes)
+
+ return app
+}
+
/*
START OF USERS ROUTER
*/
@@ -52,7 +51,7 @@ func main() {
func registerUsersRoutes(usersRouter iris.Party) {
// GET: /users
usersRouter.Get("/", getAllUsersHandler)
- usersRouter.PartyFunc("/{name:string}", registerUserRoutes)
+ usersRouter.Party("/{name}").ConfigureContainer(registerUserRoutes)
}
type user struct {
@@ -78,16 +77,12 @@ func getAllUsersHandler(ctx iris.Context) {
START OF USERS.USER SUB ROUTER
*/
-func registerUserRoutes(userRouter iris.Party) {
- // create a new dependency injection manager for this sub router.
- userDeps := hero.New()
- // you can also use the global/package-level hero.Register(userDependency) as we have already learned in other examples.
- userDeps.Register(userDependency)
-
+func registerUserRoutes(userRouter *iris.APIContainer) {
+ userRouter.RegisterDependency(userDependency)
// GET: /users/{name:string}
- userRouter.Get("/", userDeps.Handler(getUserHandler))
+ userRouter.Get("/", getUserHandler)
// GET: /users/{name:string}/age
- userRouter.Get("/age", userDeps.Handler(getUserAgeHandler))
+ userRouter.Get("/age", getUserAgeHandler)
}
var userDependency = func(ctx iris.Context) *user {
@@ -108,30 +103,12 @@ var userDependency = func(ctx iris.Context) *user {
}
func getUserHandler(ctx iris.Context, u *user) {
- if u == nil {
- return
- }
-
sendJSON(ctx, u)
}
-func getUserAgeHandler(ctx iris.Context, u *user) {
- if u == nil {
- return
- }
-
- ctx.Writef("%d", u.Age)
-}
-
-/* Remember, with 'hero' you get mvc-like functions, so this can work too:
func getUserAgeHandler(u *user) string {
- if u == nil {
- return ""
- }
-
return fmt.Sprintf("%d", u.Age)
}
-*/
/* END OF USERS.USER SUB ROUTER */
@@ -158,11 +135,8 @@ func fail(ctx iris.Context, statusCode int, format string, a ...interface{}) {
ctx.Application().Logger().Error(err)
}
- ctx.StatusCode(statusCode)
- ctx.JSON(err)
-
// no next handlers will run.
- ctx.StopExecution()
+ ctx.StopWithJSON(statusCode, err)
}
// JSON helper to give end-user the ability to put indention chars or filtering the response, you can do that, optionally.
@@ -177,6 +151,6 @@ func sendJSON(ctx iris.Context, resp interface{}) (err error) {
}
}
- _, err = ctx.JSON(resp, context.JSON{Indent: indent, UnescapeHTML: true})
+ _, err = ctx.JSON(resp, iris.JSON{Indent: indent, UnescapeHTML: true})
return err
}
diff --git a/_examples/hero/basic/README.md b/_examples/hero/basic/README.md
deleted file mode 100644
index 88309fb5..00000000
--- a/_examples/hero/basic/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# hero: basic
-
-## 1. Path Parameters - Builtin Dependencies
-
-![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png)
-
-## 2. Services - Static Dependencies
-
-![](https://github.com/kataras/explore/raw/master/iris/hero/hero-2-monokai.png)
-
-## 3. Per-Request - Dynamic Dependencies
-
-![](https://github.com/kataras/explore/raw/master/iris/hero/hero-3-monokai.png)
\ No newline at end of file
diff --git a/_examples/hero/basic/main.go b/_examples/hero/basic/main.go
deleted file mode 100644
index 88214b14..00000000
--- a/_examples/hero/basic/main.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package main
-
-import (
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/hero"
-)
-
-func main() {
- app := iris.New()
-
- // 1
- helloHandler := hero.Handler(hello)
- app.Get("/{to:string}", helloHandler)
-
- // 2
- hero.Register(&myTestService{
- prefix: "Service: Hello",
- })
-
- helloServiceHandler := hero.Handler(helloService)
- app.Get("/service/{to:string}", helloServiceHandler)
-
- // 3
- hero.Register(func(ctx iris.Context) (form LoginForm) {
- // it binds the "form" with a
- // x-www-form-urlencoded form data and returns it.
- ctx.ReadForm(&form)
- return
- })
-
- loginHandler := hero.Handler(login)
- app.Post("/login", loginHandler)
-
- // http://localhost:8080/your_name
- // http://localhost:8080/service/your_name
- app.Listen(":8080")
-}
-
-func hello(to string) string {
- return "Hello " + to
-}
-
-type Service interface {
- SayHello(to string) string
-}
-
-type myTestService struct {
- prefix string
-}
-
-func (s *myTestService) SayHello(to string) string {
- return s.prefix + " " + to
-}
-
-func helloService(to string, service Service) string {
- return service.SayHello(to)
-}
-
-type LoginForm struct {
- Username string `form:"username"`
- Password string `form:"password"`
-}
-
-func login(form LoginForm) string {
- return "Hello " + form.Username
-}
diff --git a/_examples/hero/overview/main.go b/_examples/hero/overview/main.go
deleted file mode 100644
index 264ed5b1..00000000
--- a/_examples/hero/overview/main.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// file: main.go
-
-package main
-
-import (
- "github.com/kataras/iris/v12/_examples/hero/overview/datasource"
- "github.com/kataras/iris/v12/_examples/hero/overview/repositories"
- "github.com/kataras/iris/v12/_examples/hero/overview/services"
- "github.com/kataras/iris/v12/_examples/hero/overview/web/middleware"
- "github.com/kataras/iris/v12/_examples/hero/overview/web/routes"
-
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/hero"
-)
-
-func main() {
- app := iris.New()
- app.Logger().SetLevel("debug")
-
- // Load the template files.
- app.RegisterView(iris.HTML("./web/views", ".html"))
-
- // Create our movie repository with some (memory) data from the datasource.
- repo := repositories.NewMovieRepository(datasource.Movies)
- // Create our movie service, we will bind it to the movie app's dependencies.
- movieService := services.NewMovieService(repo)
- hero.Register(movieService)
-
- // Serve our routes with hero handlers.
- app.PartyFunc("/hello", func(r iris.Party) {
- r.Get("/", hero.Handler(routes.Hello))
- r.Get("/{name}", hero.Handler(routes.HelloName))
- })
-
- app.PartyFunc("/movies", func(r iris.Party) {
- // Add the basic authentication(admin:password) middleware
- // for the /movies based requests.
- r.Use(middleware.BasicAuth)
-
- r.Get("/", hero.Handler(routes.Movies))
- r.Get("/{id:long}", hero.Handler(routes.MovieByID))
- r.Put("/{id:long}", hero.Handler(routes.UpdateMovieByID))
- r.Delete("/{id:long}", hero.Handler(routes.DeleteMovieByID))
- })
-
- // http://localhost:8080/hello
- // http://localhost:8080/hello/iris
- // http://localhost:8080/movies
- // http://localhost:8080/movies/1
- app.Run(
- // Start the web server at localhost:8080
- iris.Addr("localhost:8080"),
- // enables faster json serialization and more:
- iris.WithOptimizations,
- )
-}
diff --git a/_examples/hero/sessions/main.go b/_examples/hero/sessions/main.go
deleted file mode 100644
index 4a9da3c1..00000000
--- a/_examples/hero/sessions/main.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package main
-
-import (
- "time"
-
- "github.com/kataras/iris/v12/_examples/hero/sessions/routes"
-
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/hero" // <- IMPORTANT
- "github.com/kataras/iris/v12/sessions"
-)
-
-func main() {
- app := iris.New()
- sessionManager := sessions.New(sessions.Config{
- Cookie: "site_session_id",
- Expires: 60 * time.Minute,
- AllowReclaim: true,
- })
-
- // Register
- // dynamic dependencies like the *sessions.Session, from `sessionManager.Start(ctx) *sessions.Session` <- it accepts a Context and it returns
- // something -> this is called dynamic request-time dependency and that "something" can be used to your handlers as input parameters,
- // no limit about the number of dependencies, each handler will be builded once, before the server ran and it will use only dependencies that it needs.
- hero.Register(sessionManager.Start)
- // convert any function to an iris Handler, their input parameters are being resolved using the unique Iris' blazing-fast dependency injection
- // for services or dynamic dependencies like the *sessions.Session, from sessionManager.Start(ctx) *sessions.Session) <- it accepts a context and it returns
- // something-> this is called dynamic request-time dependency.
- indexHandler := hero.Handler(routes.Index)
-
- // Method: GET
- // Path: http://localhost:8080
- app.Get("/", indexHandler)
-
- app.Listen(":8080")
-}
diff --git a/_examples/hero/sessions/routes/index.go b/_examples/hero/sessions/routes/index.go
deleted file mode 100644
index 2d3611ad..00000000
--- a/_examples/hero/sessions/routes/index.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package routes
-
-import (
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/sessions"
-)
-
-// Index will increment a simple int version based on the visits that this user/session did.
-func Index(ctx iris.Context, session *sessions.Session) {
- // it increments a "visits" value of integer by one,
- // if the entry with key 'visits' doesn't exist it will create it for you.
- visits := session.Increment("visits", 1)
-
- // write the current, updated visits.
- ctx.Writef("%d visit(s) from my current session", visits)
-}
-
-/*
-You can also do anything that an MVC function can, i.e:
-
-func Index(ctx iris.Context,session *sessions.Session) string {
- visits := session.Increment("visits", 1)
- return fmt.Spritnf("%d visit(s) from my current session", visits)
-}
-// you can also omit iris.Context input parameter and use dependency injection for LoginForm and etc. <- look the mvc examples.
-*/
diff --git a/_examples/subdomains/single/main.go b/_examples/subdomains/single/main.go
index 2ecb7f43..ef972c05 100644
--- a/_examples/subdomains/single/main.go
+++ b/_examples/subdomains/single/main.go
@@ -8,10 +8,8 @@ import (
func main() {
app := iris.New()
- // subdomains works with all available routers, like other features too.
-
- // no order, you can register subdomains at the end also.
- admin := app.Party("admin.")
+ // Subdomain method is just another Party.
+ admin := app.Subdomain("admin")
{
// admin.mydomain.com
admin.Get("/", func(c iris.Context) {
@@ -27,7 +25,7 @@ func main() {
})
}
- // mydomain.com/
+ // mydomain.com
app.Get("/", func(c iris.Context) {
c.Writef("INDEX FROM no-subdomain hey")
})
diff --git a/_examples/tutorial/vuejs-todo-mvc/README.md b/_examples/tutorial/vuejs-todo-mvc/README.md
index 63a67671..34296b4d 100644
--- a/_examples/tutorial/vuejs-todo-mvc/README.md
+++ b/_examples/tutorial/vuejs-todo-mvc/README.md
@@ -498,57 +498,65 @@ And finally our main application's endpoint.
package main
import (
- "vuejs-todo-mvc/todo"
- "vuejs-todo-mvc/web/controllers"
+ "strings"
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/sessions"
- "github.com/kataras/iris/v12/websocket"
+ "github.com/kataras/iris/v12/_examples/tutorial/vuejs-todo-mvc/src/todo"
+ "github.com/kataras/iris/v12/_examples/tutorial/vuejs-todo-mvc/src/web/controllers"
- "github.com/kataras/iris/v12/mvc"
+ "github.com/kataras/iris/v12"
+ "github.com/kataras/iris/v12/mvc"
+ "github.com/kataras/iris/v12/sessions"
+ "github.com/kataras/iris/v12/websocket"
)
func main() {
- app := iris.New()
+ app := iris.New()
- // serve our app in public, public folder
- // contains the client-side vue.js application,
- // no need for any server-side template here,
- // actually if you're going to just use vue without any
- // back-end services, you can just stop afer this line and start the server.
- app.HandleDir("/", "./public")
+ // serve our app in public, public folder
+ // contains the client-side vue.js application,
+ // no need for any server-side template here,
+ // actually if you're going to just use vue without any
+ // back-end services, you can just stop afer this line and start the server.
+ app.HandleDir("/", "./public")
- // configure the http sessions.
- sess := sessions.New(sessions.Config{
- Cookie: "iris_session",
- })
+ // configure the http sessions.
+ sess := sessions.New(sessions.Config{
+ Cookie: "iris_session",
+ })
- // configure the websocket server.
- ws := websocket.New(websocket.Config{})
+ // create a sub router and register the http controllers.
+ todosRouter := app.Party("/todos")
- // create a sub router and register the client-side library for the iris websockets,
- // you could skip it but iris websockets supports socket.io-like API.
- todosRouter := app.Party("/todos")
- // http://localhost:8080/todos/iris-ws.js
- // serve the javascript client library to communicate with
- // the iris high level websocket event system.
- todosRouter.Any("/iris-ws.js", websocket.ClientHandler())
+ // create our mvc application targeted to /todos relative sub path.
+ todosApp := mvc.New(todosRouter)
- // create our mvc application targeted to /todos relative sub path.
- todosApp := mvc.New(todosRouter)
+ // any dependencies bindings here...
+ todosApp.Register(
+ todo.NewMemoryService(),
+ )
- // any dependencies bindings here...
- todosApp.Register(
- todo.NewMemoryService(),
- sess.Start,
- ws.Upgrade,
- )
+ todosController := new(controllers.TodoController)
+ // controllers registration here...
+ todosApp.Handle(todosController)
- // controllers registration here...
- todosApp.Handle(new(controllers.TodoController))
+ // Create a sub mvc app for websocket controller.
+ // Inherit the parent's dependencies.
+ todosWebsocketApp := todosApp.Party("/sync")
+ todosWebsocketApp.HandleWebsocket(todosController).
+ SetNamespace("todos").
+ SetEventMatcher(func(methodName string) (string, bool) {
+ return strings.ToLower(methodName), true
+ })
- // start the web server at http://localhost:8080
- app.Listen(":8080")
+ websocketServer := websocket.New(websocket.DefaultGorillaUpgrader, todosWebsocketApp)
+ idGenerator := func(ctx iris.Context) string {
+ id := sess.Start(ctx).ID()
+ return id
+ }
+ todosWebsocketApp.Router.Get("/", websocket.Handler(websocketServer, idGenerator))
+
+ // start the web server at http://localhost:8080
+ app.Listen(":8080")
}
```
diff --git a/_examples/tutorial/vuejs-todo-mvc/src/web/main.go b/_examples/tutorial/vuejs-todo-mvc/src/web/main.go
index 75f0800d..a47989e0 100644
--- a/_examples/tutorial/vuejs-todo-mvc/src/web/main.go
+++ b/_examples/tutorial/vuejs-todo-mvc/src/web/main.go
@@ -36,7 +36,6 @@ func main() {
// any dependencies bindings here...
todosApp.Register(
todo.NewMemoryService(),
- sess.Start,
)
todosController := new(controllers.TodoController)
diff --git a/core/router/api_container.go b/core/router/api_container.go
index 5a565f70..ab1d4f03 100644
--- a/core/router/api_container.go
+++ b/core/router/api_container.go
@@ -26,6 +26,14 @@ func (api *APIContainer) Party(relativePath string, handlersFn ...interface{}) *
return p.ConfigureContainer()
}
+// PartyFunc same as `Party` but it accepts a party builder function instead.
+// Returns the new Party's APIContainer
+func (api *APIContainer) PartyFunc(relativePath string, fn func(*APIContainer)) *APIContainer {
+ childContainer := api.Party(relativePath)
+ fn(childContainer)
+ return childContainer
+}
+
// OnError adds an error handler for this Party's DI Hero Container and its handlers (or controllers).
// The "errorHandler" handles any error may occurred and returned
// during dependencies injection of the Party's hero handlers or from the handlers themselves.
@@ -89,6 +97,14 @@ func (api *APIContainer) convertHandlerFuncs(relativePath string, handlersFn ...
return handlers
}
+// Handler receives a function which can receive dependencies and output result
+// and returns a common Iris Handler, useful for Versioning API integration otherwise
+// the `Handle/Get/Post...` methods are preferable.
+func (api *APIContainer) Handler(handlerFn interface{}, handlerParamsCount int) context.Handler {
+ paramsCount := macro.CountParams(api.Self.GetRelPath(), *api.Self.Macros()) + handlerParamsCount
+ return api.Container.HandlerWithParams(handlerFn, paramsCount)
+}
+
// Use same as `Self.Use` but it accepts dynamic functions as its "handlersFn" input.
//
// See `OnError`, `RegisterDependency`, `Done` and `Handle` for more.
diff --git a/core/router/route.go b/core/router/route.go
index 31b51d91..b89650ad 100644
--- a/core/router/route.go
+++ b/core/router/route.go
@@ -4,6 +4,7 @@ import (
"fmt"
"io"
"net/http"
+ "path/filepath"
"strings"
"time"
@@ -342,7 +343,7 @@ func (r *Route) ResolvePath(args ...string) string {
}
func traceHandlerFile(method, name, line string, number int) string {
- file := fmt.Sprintf("(%s:%d)", line, number)
+ file := fmt.Sprintf("(%s:%d)", filepath.ToSlash(line), number)
if context.IgnoreHandlerName(name) {
return ""
diff --git a/hero/func_result.go b/hero/func_result.go
index bd6d1ab7..70670e4a 100644
--- a/hero/func_result.go
+++ b/hero/func_result.go
@@ -54,7 +54,7 @@ func defaultResultHandler(ctx context.Context, v interface{}) error {
// All types that complete this interface
// can be returned as values from the method functions.
//
-// Example at: https://github.com/kataras/iris/tree/master/_examples/hero/overview.
+// Example at: https://github.com/kataras/iris/tree/master/_examples/dependency-injection/overview.
type Result interface {
// Dispatch should send a response to the client.
Dispatch(context.Context)
@@ -436,7 +436,7 @@ func (r Response) Dispatch(ctx context.Context) {
// wraps the template file name, layout, (any) view data, status code and error.
// It's smart enough to complete the request and send the correct response to the client.
//
-// Example at: https://github.com/kataras/iris/blob/master/_examples/hero/overview/web/routes/hello.go.
+// Example at: https://github.com/kataras/iris/blob/master/_examples/dependency-injection/overview/web/routes/hello.go.
type View struct {
Name string
Layout string
diff --git a/hero/handler.go b/hero/handler.go
index 4e6b72e6..ca9512e9 100644
--- a/hero/handler.go
+++ b/hero/handler.go
@@ -103,6 +103,13 @@ func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler
return
}
+ // If ~an error status code is set or~ execution has stopped
+ // from within the dependency (something went wrong while validating the request),
+ // then stop everything and let handler fire that status code.
+ if ctx.IsStopped() /* || context.StatusCodeNotSuccessful(ctx.GetStatusCode())*/ {
+ return
+ }
+
inputs[binding.Input.Index] = input
}
diff --git a/versioning/README.md b/versioning/README.md
deleted file mode 100644
index 01a629ad..00000000
--- a/versioning/README.md
+++ /dev/null
@@ -1,142 +0,0 @@
-# Versioning
-
-The [versioning](https://github.com/kataras/iris/tree/master/versioning) package provides [semver](https://semver.org/) versioning for your APIs. It implements all the suggestions written at [api-guidelines](https://github.com/byrondover/api-guidelines/blob/master/Guidelines.md#versioning) and more.
-
-
-The version comparison is done by the [go-version](https://github.com/hashicorp/go-version) package. It supports matching over patterns like `">= 1.0, < 3"` and etc.
-
-## Features
-
-- per route version matching, a normal iris handler with "switch" cases via Map for version => handler
-- per group versioned routes and deprecation API
-- version matching like ">= 1.0, < 2.0" or just "2.0.1" and etc.
-- version not found handler (can be customized by simply adding the versioning.NotFound: customNotMatchVersionHandler on the Map)
-- version is retrieved from the "Accept" and "Accept-Version" headers (can be customized via middleware)
-- respond with "X-API-Version" header, if version found.
-- deprecation options with customizable "X-API-Warn", "X-API-Deprecation-Date", "X-API-Deprecation-Info" headers via `Deprecated` wrapper.
-
-## Get version
-
-Current request version is retrieved by `versioning.GetVersion(ctx)`.
-
-By default the `GetVersion` will try to read from:
-- `Accept` header, i.e `Accept: "application/json; version=1.0"`
-- `Accept-Version` header, i.e `Accept-Version: "1.0"`
-
-You can also set a custom version for a handler via a middleware by using the context's store values.
-For example:
-```go
-func(ctx iris.Context) {
- ctx.Values().Set(versioning.Key, ctx.URLParamDefault("version", "1.0"))
- ctx.Next()
-}
-```
-
-## Match version to handler
-
-The `versioning.NewMatcher(versioning.Map) iris.Handler` creates a single handler which decides what handler need to be executed based on the requested version.
-
-```go
-app := iris.New()
-
-// middleware for all versions.
-myMiddleware := func(ctx iris.Context) {
- // [...]
- ctx.Next()
-}
-
-myCustomNotVersionFound := func(ctx iris.Context) {
- ctx.StatusCode(404)
- ctx.Writef("%s version not found", versioning.GetVersion(ctx))
-}
-
-userAPI := app.Party("/api/user")
-userAPI.Get("/", myMiddleware, versioning.NewMatcher(versioning.Map{
- "1.0": sendHandler(v10Response),
- ">= 2, < 3": sendHandler(v2Response),
- versioning.NotFound: myCustomNotVersionFound,
-}))
-```
-
-### Deprecation
-
-Using the `versioning.Deprecated(handler iris.Handler, options versioning.DeprecationOptions) iris.Handler` function you can mark a specific handler version as deprecated.
-
-
-```go
-v10Handler := versioning.Deprecated(sendHandler(v10Response), versioning.DeprecationOptions{
- // if empty defaults to: "WARNING! You are using a deprecated version of this API."
- WarnMessage string
- DeprecationDate time.Time
- DeprecationInfo string
-})
-
-userAPI.Get("/", versioning.NewMatcher(versioning.Map{
- "1.0": v10Handler,
- // [...]
-}))
-```
-
-This will make the handler to send these headers to the client:
-
-- `"X-API-Warn": options.WarnMessage`
-- `"X-API-Deprecation-Date": context.FormatTime(ctx, options.DeprecationDate))`
-- `"X-API-Deprecation-Info": options.DeprecationInfo`
-
-> versioning.DefaultDeprecationOptions can be passed instead if you don't care about Date and Info.
-
-## Grouping routes by version
-
-Grouping routes by version is possible as well.
-
-Using the `versioning.NewGroup(version string) *versioning.Group` function you can create a group to register your versioned routes.
-The `versioning.RegisterGroups(r iris.Party, versionNotFoundHandler iris.Handler, groups ...*versioning.Group)` must be called in the end in order to register the routes to a specific `Party`.
-
-```go
-app := iris.New()
-
-userAPI := app.Party("/api/user")
-// [... static serving, middlewares and etc goes here].
-
-userAPIV10 := versioning.NewGroup("1.0")
-userAPIV10.Get("/", sendHandler(v10Response))
-
-userAPIV2 := versioning.NewGroup(">= 2, < 3")
-userAPIV2.Get("/", sendHandler(v2Response))
-userAPIV2.Post("/", sendHandler(v2Response))
-userAPIV2.Put("/other", sendHandler(v2Response))
-
-versioning.RegisterGroups(userAPI, versioning.NotFoundHandler, userAPIV10, userAPIV2)
-```
-
-> A middleware can be registered to the actual `iris.Party` only, using the methods we learnt above, i.e by using the `versioning.Match` in order to detect what code/handler you want to be executed when "x" or no version is requested.
-
-### Deprecation for Group
-
-Just call the `Deprecated(versioning.DeprecationOptions)` on the group you want to notify your API consumers that this specific version is deprecated.
-
-```go
-userAPIV10 := versioning.NewGroup("1.0").Deprecated(versioning.DefaultDeprecationOptions)
-```
-
-## Compare version manually from inside your handlers
-
-```go
-// reports if the "version" is matching to the "is".
-// the "is" can be a constraint like ">= 1, < 3".
-If(version string, is string) bool
-```
-
-```go
-// same as `If` but expects a Context to read the requested version.
-Match(ctx iris.Context, expectedVersion string) bool
-```
-
-```go
-app.Get("/api/user", func(ctx iris.Context) {
- if versioning.Match(ctx, ">= 2.2.3") {
- // [logic for >= 2.2.3 version of your handler goes here]
- return
- }
-})
-```
\ No newline at end of file