new simple _examples/README.md, wiki should live only inside kataras/iris/wiki and the provided e-book

Former-commit-id: 350eafb0f70f8433e394e103ff93fa332ee00a05
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-05-05 16:03:19 +03:00
parent f5e59c10e1
commit c10dd32ad7
28 changed files with 416 additions and 1166 deletions

View File

@ -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
<!-- [![Run in Postman](https://run.pstmn.io/button.svg)](https://www.getpostman.com/collections/16e76a9528aba863e821) -->
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
<details>
<summary>External packages</summary>
```sh
cd _examples && go get ./...
```
</details>
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)

View File

@ -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("<b>Hello!</b>")
})
// [...]
// 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("<b>Hello!</b>")
})
// [...]
// 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("<b>Hello!</b>")
})
// [...]
// 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("<b>Hello!</b>")
})
// [...]
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")
}
```

View File

@ -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"`

View File

@ -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",

View File

@ -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,
)
}

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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,
)
}

View File

@ -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")
}

View File

@ -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.
*/

View File

@ -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")
})

View File

@ -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")
}
```

View File

@ -36,7 +36,6 @@ func main() {
// any dependencies bindings here...
todosApp.Register(
todo.NewMemoryService(),
sess.Start,
)
todosController := new(controllers.TodoController)

View File

@ -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.

View File

@ -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 ""

View File

@ -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

View File

@ -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
}

View File

@ -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
}
})
```