mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
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:
parent
f5e59c10e1
commit
c10dd32ad7
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
```
|
|
@ -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"`
|
|
@ -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",
|
55
_examples/dependency-injection/overview/main.go
Normal file
55
_examples/dependency-injection/overview/main.go
Normal 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,
|
||||
)
|
||||
}
|
|
@ -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.
|
|
@ -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)
|
|
@ -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
|
34
_examples/dependency-injection/sessions/main.go
Normal file
34
_examples/dependency-injection/sessions/main.go
Normal 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)
|
||||
}
|
17
_examples/dependency-injection/sessions/routes/index.go
Normal file
17
_examples/dependency-injection/sessions/routes/index.go
Normal 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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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.
|
||||
*/
|
|
@ -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")
|
||||
})
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ func main() {
|
|||
// any dependencies bindings here...
|
||||
todosApp.Register(
|
||||
todo.NewMemoryService(),
|
||||
sess.Start,
|
||||
)
|
||||
|
||||
todosController := new(controllers.TodoController)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
})
|
||||
```
|
Loading…
Reference in New Issue
Block a user