From bb1a93d7fd16b8ef17ccfb84eff20674dce56b2b Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Mon, 22 Jul 2019 04:32:54 +0300 Subject: [PATCH] touches before release Former-commit-id: c6539320214e9120a801b2a3c3c8e9867dfb2ed7 --- FAQ.md | 2 +- HISTORY.md | 970 +-------------- HISTORY_GR.md | 331 +---- HISTORY_ID.md | 410 +------ HISTORY_ZH.md | 398 +----- README.md | 1027 +--------------- _examples/websocket/basic/server.go | 18 +- cache/cache.go | 22 +- context/context.go | 22 +- doc.go | 1755 +-------------------------- iris.go | 19 +- 11 files changed, 59 insertions(+), 4915 deletions(-) diff --git a/FAQ.md b/FAQ.md index 451f584a..f9e9f26f 100644 --- a/FAQ.md +++ b/FAQ.md @@ -21,7 +21,7 @@ Add a `badge` to your open-source projects powered by [Iris](https://iris-go.com ## How to upgrade ```sh -go get -u github.com/kataras/iris +go get github.com/kataras/iris@v11.2.0 ``` Go version 1.12 and above is required. diff --git a/HISTORY.md b/HISTORY.md index b84b61b7..6bfb705a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -13,972 +13,6 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready. -**How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris` or let the automatic updater do that for you. +**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris@v11.2.0`. -# Soon - -Coming soon, stay tuned by reading the [PR](https://github.com/kataras/iris/pull/1175) progress. - -# Fr, 11 January 2019 | v11.1.1 - -Happy new year! This is a minor release, contains mostly bug fixes. - -Strange that we don't have major features in this release, right? Don't worry, I am not out of ideas (at least not yet!). -I have some features in-mind but lately I do not have the time to humanize those ideas for you due to my new position in [Netdata Inc.](https://github.com/netdata/netdata), so be patient and [stay-tuned](https://github.com/kataras/iris/stargazers). Read the current changelog below: - -- session/redis: fix unused service config var. IdleTimeout witch was replaced by default values. [#1140](https://github.com/kataras/iris/pull/1140) ([@d7561985](https://github.com/d7561985)) - -- fix [#1141](https://github.com/kataras/iris/issues/1141) and [#1142](https://github.com/kataras/iris/issues/1142). [2bd7a8e88777766d1f4cac7562feec304112d2b1](https://github.com/kataras/iris/commit/2bd7a8e88777766d1f4cac7562feec304112d2b1) (@kataras) - -- fix cache corruption due to recorder reuse. [#1146](https://github.com/kataras/iris/pull/1146) ([@Slamper](https://github.com/Slamper)) - -- add `StatusTooEarly`, compatible with: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/425#Browser_compatibility. [31b2913447aa9e41e16a3eb33eb0019427e15cea](https://github.com/kataras/iris/commit/31b2913447aa9e41e16a3eb33eb0019427e15cea) (@kataras) - -- fix [#1164](https://github.com/kataras/iris/issues/1164). [701e8e46c20395f87fa34bf9fabd145074c7b78c](https://github.com/kataras/iris/commit/701e8e46c20395f87fa34bf9fabd145074c7b78c) (@kataras) - -- `context#ReadForm` can skip unkown fields by `IsErrPath(err)`, fixes: [#1157](https://github.com/kataras/iris/issues/1157). [1607bb5113568af6a34142f23bfa44903205b314](https://github.com/kataras/iris/commit/1607bb5113568af6a34142f23bfa44903205b314) (@kataras) - - -Doc updates: - -- fix grammar and misspell. [5069e9afd8700d20dfd04cdc008efd671b5d0b40](https://github.com/kataras/iris/commit/5069e9afd8700d20dfd04cdc008efd671b5d0b40) (@kataras) - -- fix link for httpexpect in README. [#1148](https://github.com/kataras/iris/pull/1148) ([@drenel18](https://github.com/drenel18)) - -- translate _examples/README.md into Chinese. [#1156](https://github.com/kataras/iris/pull/1156) ([@fduxiao](https://github.com/fduxiao)) - -- add https://github.com/snowlyg/IrisApiProject to starter kits (Chinese). [ea12533871253afc34e40e36ba658b51955ea82d](https://github.com/kataras/iris/commit/ea12533871253afc34e40e36ba658b51955ea82d) - -- add https://github.com/yz124/superstar to starter kits (Chinese). [0e734ff8445f07482c28881347c1e564dc5aab9c](https://github.com/kataras/iris/commit/0e734ff8445f07482c28881347c1e564dc5aab9c) - -# Su, 18 November 2018 | v11.1.0 - -PR: https://github.com/kataras/iris/pull/1130 - -This release contains a new feature for versioning your Iris APIs. The initial motivation and feature request came by https://github.com/kataras/iris/issues/1129. - -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 - } -}) -``` - -Example can be found [here](_examples/versioning/main.go). - -# Fr, 09 November 2018 | v11.0.4 - -Add `Configuration.DisablePathCorrectionRedirection` - `iris.WithoutPathCorrectionRedirection` to support -direct handler execution of the matching route without the last `'/'` instead of sending a redirect response when `DisablePathCorrection` is set to false(default behavior). - -Usage: - -For example, CORS needs the allow origin headers in redirect response as well, -however is not possible from the router to know what headers a route's handler will send to the client. -So the best option we have is to just execute the handler itself instead of sending a redirect response. -Add the `app.Run(..., iris.WithoutPathCorrectionRedirection)` on the server side if you wish -to directly fire the handler instead of redirection (which is the default behavior) -on request paths like `"$yourdomain/v1/mailer/"` when `"/v1/mailer"` route handler is registered. - -Example Code: - -```go -package main - -import "github.com/kataras/iris" - - -func main() { - app := iris.New() - - crs := func(ctx iris.Context) { - ctx.Header("Access-Control-Allow-Origin", "*") - ctx.Header("Access-Control-Allow-Credentials", "true") - ctx.Header("Access-Control-Allow-Headers", - "Access-Control-Allow-Origin,Content-Type") - ctx.Next() - } - - v1 := app.Party("/api/v1", crs).AllowMethods(iris.MethodOptions) - { - v1.Post("/mailer", func(ctx iris.Context) { - var any iris.Map - err := ctx.ReadJSON(&any) - if err != nil { - ctx.WriteString(err.Error()) - ctx.StatusCode(iris.StatusBadRequest) - return - } - ctx.Application().Logger().Infof("received %#+v", any) - }) - } - - // HERE: - app.Run(iris.Addr(":80"), iris.WithoutPathCorrectionRedirection) -} -``` - -# Tu, 06 November 2018 | v11.0.3 - -- add "part" html view engine's tmpl function: [15bb55d](https://github.com/kataras/iris/commit/15bb55d85eac378bbe0c98c10ffea938cc05fe4d) - -- update pug engine's vendor: [c20bc3b](https://github.com/kataras/iris/commit/c20bc3bceef158ef99931e609123fa0aca2a918c) - -# Tu, 30 October 2018 | v11.0.2 - -Fix [memstore](core/memstore/memstore.go) overflows when build 32 bit app, reported and fixed by [@bouroo](https://github.com/bouroo) at: https://github.com/kataras/iris/issues/1118 - -# Su, 28 October 2018 | v11.0.1 - -- Update benchmarks: https://github.com/kataras/iris/commit/d1b47b1ec65ae77a2ca7485e510386f4a5456ac4 -- Add link for third-party source benchmarks: https://github.com/kataras/iris/commit/64e80a7ee5c23ed938ddc8b68d181a25420c7653 -- Add optionally custom low-level websocket message data prefix as requested at: https://github.com/kataras/iris/issues/1113 by [@jjhesk](https://github.com/jjhesk). Example: - -```go -app := iris.New() - -// [...] -wsServer := websocket.New(websocket.Config{ - // [...] - EvtMessagePrefix: []byte("my-custom-prefix:"), -}) - -// [...] - -// serve the javascript built-in client-side library, -// see websockets.html script tags, this path is used. -app.Any("/iris-ws.js", func(ctx iris.Context) { - ctx.Write(wsServer.ClientSource) -}) - -// [...] -``` - -# Su, 21 October 2018 | v11.0.0 - -For the craziest of us, click [here](https://github.com/kataras/iris/compare/v10.7.0...v11) 🔥 to find out the commits and the code changes since our previous release. - -## Breaking changes - -- Remove the "Configurator" `WithoutVersionChecker` and the configuration field `DisableVersionChecker` -- `:int` parameter type **can accept negative numbers now**. -- `app.Macros().String/Int/Uint64/Path...RegisterFunc` should be replaced to: `app.Macros().Get("string" or "int" or "uint64" or "path" when "path" is the ":path" parameter type).RegisterFunc`, because you can now add custom macros and parameter types as well, see [here](_examples/routing/macros). -- `RegisterFunc("min", func(paramValue string) bool {...})` should be replaced to `RegisterFunc("min", func(paramValue ) bool {...})`, the `paramValue` argument is now stored in the exact type the macro's type evaluator inits it, i.e `uint64` or `int` and so on, therefore you don't have to convert the parameter value each time (this should make your handlers with macro functions activated even faster now) -- The `Context#ReadForm` will no longer return an error if it has no value to read from the request, we let those checks to the caller and validators as requested at: https://github.com/kataras/iris/issues/1095 by [@haritsfahreza](https://github.com/haritsfahreza) - -## Routing - -I wrote a [new router implementation](https://github.com/kataras/muxie#philosophy) for our Iris internal(low-level) routing mechanism, it is good to know that this was the second time we have updated the router internals without a single breaking change after the v6, thanks to the very well-written and designed-first code we have for the high-level path syntax component called [macro interpreter](macro/interpreter). - -The new router supports things like **closest wildcard resolution**. - -> If the name doesn't sound good to you it is because I named that feature myself, I don't know any other framework or router that supports a thing like that so be gentle:) - -Previously you couldn't register routes like: `/{myparam:path}` and `/static` and `/{myparam:string}` and `/{myparam:string}/static` and `/static/{myparam:string}` all in one path prefix without a "decision handler". And generally if you had a wildcard it was possible to add (a single) static part and (a single) named parameter but not without performance cost and limits, why only one? (one is better than nothing: look the Iris' alternatives) We struggle to overcome our own selves, now you **can definitely do it without a bit of performance cost**, and surely we hand't imagine the wildcard to **catch all if nothing else found** without huge routing performance cost, the wildcard(`:path`) meant ONLY: "accept one or more path segments and put them into the declared parameter" so if you had register a dynamic single-path-segment named parameter like `:string, :int, :uint, :alphabetical...` in between those path segments it wouldn't work. The **closest wildcard resolution** offers you the opportunity to design your APIs even better via custom handlers and error handlers like `404 not found` to path prefixes for your API's groups, now you can do it without any custom code for path resolution inside a "decision handler" or a middleware. - -Code worths 1000 words, now it is possible to define your routes like this without any issues: - -```go -package main - -import ( - "github.com/kataras/iris" - "github.com/kataras/iris/context" -) - -func main() { - app := iris.New() - - // matches everyhing if nothing else found, - // so you can use it for custom 404 root-level/main pages! - app.Get("/{p:path}", func(ctx context.Context) { - path := ctx.Params().Get("p") - // gives the path without the first "/". - ctx.Writef("Site Custom 404 Error Message\nPage of: '%s' not found", path) - }) - - app.Get("/", indexHandler) - - // request: http://localhost:8080/profile - // response: "Profile Index" - app.Get("/profile", func(ctx context.Context) { - ctx.Writef("Profile Index") - }) - - // request: http://localhost:8080/profile/kataras - // response: "Profile of username: 'kataras'" - app.Get("/profile/{username}", func(ctx context.Context) { - username := ctx.Params().Get("username") - ctx.Writef("Profile of username: '%s'", username) - }) - - // request: http://localhost:8080/profile/settings - // response: "Profile personal settings" - app.Get("/profile/settings", func(ctx context.Context) { - ctx.Writef("Profile personal settings") - }) - - // request: http://localhost:8080/profile/settings/security - // response: "Profile personal security settings" - app.Get("/profile/settings/security", func(ctx context.Context) { - ctx.Writef("Profile personal security settings") - }) - - // matches everyhing /profile/*somethng_here* - // if no other route matches the path semgnet after the - // /profile or /profile/ - // - // So, you can use it for custom 404 profile pages - // side-by-side to your root wildcard without issues! - // For example: - // request: http://localhost:8080/profile/kataras/what - // response: - // Profile Page Custom 404 Error Message - // Profile Page of: 'kataras/what' was unable to be found - app.Get("/profile/{p:path}", func(ctx context.Context) { - path := ctx.Params().Get("p") - ctx.Writef("Profile Page Custom 404 Error Message\nProfile Page of: '%s' not found", path) - }) - - app.Run(iris.Addr(":8080")) -} - -func indexHandler(ctx context.Context) { - ctx.HTML("This is the index page") -} - -``` - -The `github.com/kataras/iris/core/router.AllMethods` is now a variable that can be altered by end-developers, so things like `app.Any` can register to custom methods as well, as requested at: https://github.com/kataras/iris/issues/1102. For example, import that package and do `router.AllMethods = append(router.AllMethods, "LINK")` in your `main` or `init` function. - -The old `github.com/kataras/iris/core/router/macro` package was moved to `guthub.com/kataras/iris/macro` to allow end-developers to add custom parameter types and macros, it supports all go standard types by default as you will see below. - -- `:int` parameter type as an alias to the old `:int` which can accept any numeric path segment now, both negative and positive numbers -- Add `:int8` parameter type and `ctx.Params().GetInt8` -- Add `:int16` parameter type and `ctx.Params().GetInt16` -- Add `:int32` parameter type and `ctx.Params().GetInt32` -- Add `:int64` parameter type and `ctx.Params().GetInt64` -- Add `:uint` parameter type and `ctx.Params().GetUint` -- Add `:uint8` parameter type and `ctx.Params().GetUint8` -- Add `:uint16` parameter type and `ctx.Params().GetUint16` -- Add `:uint32` parameter type and `ctx.Params().GetUint32` -- Add `:uint64` parameter type and `ctx.Params().GetUint64` -- Add alias `:bool` for the `:boolean` parameter type - -Here is the full list of the built-in parameter types that we support now, including their validations/path segment rules. - -| Param Type | Go Type | Validation | Retrieve Helper | -| -----------------|------|-------------|------| -| `:string` | string | the default if param type is missing, anything (single path segment) | `Params().Get` | -| `:int` | int | -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch | `Params().GetInt` | -| `:int8` | int8 | -128 to 127 | `Params().GetInt8` | -| `:int16` | int16 | -32768 to 32767 | `Params().GetInt16` | -| `:int32` | int32 | -2147483648 to 2147483647 | `Params().GetInt32` | -| `:int64` | int64 | -9223372036854775808 to 9223372036854775807 | `Params().GetInt64` | -| `:uint` | uint | 0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32), depends on the host arch | `Params().GetUint` | -| `:uint8` | uint8 | 0 to 255 | `Params().GetUint8` | -| `:uint16` | uint16 | 0 to 65535 | `Params().GetUint16` | -| `:uint32` | uint32 | 0 to 4294967295 | `Params().GetUint32` | -| `:uint64` | uint64 | 0 to 18446744073709551615 | `Params().GetUint64` | -| `:bool` | bool | "1" or "t" or "T" or "TRUE" or "true" or "True" or "0" or "f" or "F" or "FALSE" or "false" or "False" | `Params().GetBool` | -| `:alphabetical` | string | lowercase or uppercase letters | `Params().Get` | -| `:file` | string | lowercase or uppercase letters, numbers, underscore (_), dash (-), point (.) and no spaces or other special characters that are not valid for filenames | `Params().Get` | -| `:path` | string | anything, can be separated by slashes (path segments) but should be the last part of the route path | `Params().Get` | - -**Usage**: - -```go -app.Get("/users/{id:uint64}", func(ctx iris.Context){ - id, _ := ctx.Params().GetUint64("id") - // [...] -}) -``` - -| Built-in Func | Param Types | -| -----------|---------------| -| `regexp`(expr string) | :string | -| `prefix`(prefix string) | :string | -| `suffix`(suffix string) | :string | -| `contains`(s string) | :string | -| `min`(minValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :string(char length), :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 | -| `max`(maxValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :string(char length), :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 | -| `range`(minValue, maxValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 | - -**Usage**: - -```go -app.Get("/profile/{name:alphabetical max(255)}", func(ctx iris.Context){ - name := ctx.Params().Get("name") - // len(name) <=255 otherwise this route will fire 404 Not Found - // and this handler will not be executed at all. -}) -``` - -## Vendoring - -- Rename the vendor `sessions/sessiondb/vendor/...bbolt` from `coreos/bbolt` to `etcd-io/bbolt` and update to v1.3.1, based on [that](https://github.com/etcd-io/bbolt/releases/tag/v1.3.1-etcd.7) -- Update the vendor `sessions/sessiondb/vendor/...badger` to v1.5.3 - -I believe it is soon to adapt the new [go modules](https://github.com/golang/go/wiki/Modules#table-of-contents) inside Iris, the new `go mod` command may change until go 1.12, it is still an experimental feature. -The [vendor](https://github.com/kataras/iris/tree/master/vendor) folder will be kept until the majority of Go developers get acquainted with the new `go modules`. The `go.mod` and `go.sum` files will come at `iris v12` (or `go 1.12`), we could do that on this version as well but I don't want to have half-things, versioning should be passed on import path as well and that is a large breaking change to go with it right now, so it will probably have a new path such as `github.com/kataras/iris/v12` based on a `git tag` like every Iris release (we are lucky here because we used semantic versioning from day zero). No folder re-structure inside the root git repository to split versions will ever happen, so backwards-compatibility for older go versions(before go 1.9.3) and iris versions will be not enabled by-default although it's easy for anyone to grab any version from older [releases](https://github.com/kataras/iris/releases) or branch and target that. - -# Sat, 11 August 2018 | v10.7.0 - -I am overjoyed to announce stage 1 of the the Iris Web framework **10.7 stable release is now available**. - -Version 10.7.0 is part of the official [releases](https://github.com/kataras/iris/releases). - -This release does not contain any breaking changes to existing Iris-based projects built on older versions of Iris. Iris developers can upgrade with absolute safety. - -Read below the changes and the improvements to the framework's internals. We also have more examples for beginners in our community. - -## New Examples - -- [Iris + WebAssemply = 💓](_examples/webassembly/basic/main.go) **compatible only for projects built with go11.beta and above** -- [Server-Sent Events](_examples/http_responsewriter/sse/main.go) -- [Struct Validation on context.ReadJSON](_examples/http_request/read-json-struct-validation/main.go) -- [Extract referrer from "referer" header or URL query parameter](_examples/http_request/extract-referer/main.go) -- [Hero Sessions](_examples/hero/sessions) -- [Yet another dependency injection example with hero](_examples/hero/smart-contract/main.go) -- [Writing an API for the Apache Kafka](_examples/tutorial/api-for-apache-kafka) - -> Also, all "sessions" examples have been customized to include the `AllowReclaim: true` option. - -## kataras/iris/websocket - -- Change connection list from a customized slice to `sync.Map` with: [this](https://github.com/kataras/iris/commit/5f16704f45bedd767527eadf411cf9bc0f8edaee) and [that commit](https://github.com/kataras/iris/commit/16b30e8eed1406c61abc01282120870bd9fa31d8) -- Minify and add the `iris-ws.js` to the famous https://cdnjs.com via [this PR](https://github.com/kataras/iris/pull/1053) made by [Dibyendu Das](https://github.com/dibyendu) - -## kataras/iris/core/router - -- Add `json` field tags and new functions such as `ChangeMethod`, `SetStatusOffline` and `RestoreStatus` to the `Route` structure, these type of changes to the routes at runtime have effect after the manual call of the `Router/Application.RefreshRouter()` (not recommended but useful for custom Iris web server's remote control panels) -- Add `GetRoutesReadOnly` function to the `APIBuilder` structure - -## kataras/iris/context - -- Add `GetReferrer`, `GetContentTypeRequested` and `URLParamInt32Default` functions -- Insert `Trace`, `Tmpl` and `MainHandlerName` functions to the `RouteReadOnly` interface -- Add `OnConnectionClose` function listener to fire a callback when the underline tcp connection is closed, extremely useful for SSE or other loop-forever implementations inside a handler -- and `OnClose` which is the same as `OnConnectionClose(myFunc)` and `defer myFunc()` [*](https://github.com/kataras/iris/commit/6898c2f755a0e22aa42e3b1799e29c857777a6f9) - -This release contains minor grammar and typo fixes and more meaningful [godoc](https://godoc.org/github.com/kataras/iris) code comments too. - -## Industry - -I am glad to announce that Iris has been chosen as the main development kit for eight medium-to-large sized companies and a new very promising India-based startup. I want to thank you once again for the unwavering support and trust you have shown me, especially this year, despite the past unfair rumours and defamation that we suffered by the merciless competition. - -# Tu, 05 June 2018 | v10.6.6 - -- **view/pug**: update vendor for Pug (Jade) parser and add [Iris + Pug examples](https://github.com/kataras/iris/tree/master/_examples#view) via [this commit](https://github.com/kataras/iris/commit/e0171cbed69efecba199ef547aa5e7063e18b27a), relative to [issue #1003](https://github.com/kataras/iris/issues/1003) opened by [@DjLeChuck](https://github.com/DjLeChuck) -- **middleware/logger**: new configuration field, defaults to false: `Query bool`, if true prints the full path, including the URL query as requested at [issue #1017](https://github.com/kataras/iris/issues/1017) by [@andr33z](https://github.com/andr33z). Example [here](https://github.com/kataras/iris/blob/master/_examples/http_request/request-logger/main.go#L21). Implemented by [this commit](https://github.com/kataras/iris/commit/a7364876e0d1b8bd60acf94f17f6d1341b16c617) -- **cookies**: some minor but helpful additions, like `CookieOption` relative to [issue #1018](https://github.com/kataras/iris/issues/1018) asked by [@dibyendu](https://github.com/dibyendu). [Cookies examples added](https://github.com/kataras/iris/tree/master/_examples/cookies) too. Implemented by [this commit](https://github.com/kataras/iris/commit/574414a64ed3d8736c836d476e6304d915f4a511) -- **cookies**: ability to set custom cookie encoders to encode the cookie's value before sent by `context#SetCookie` and `context#SetCookieKV` and cookie decoders to decode the cookie's value when retrieving from `context#GetCookie`. That was the second and final part relative to a community's question at: [issue #1018](https://github.com/kataras/iris/issues/1018). Implemented by [this commit](https://github.com/kataras/iris/commit/f708c6098faec7c4e2232c791380cdff7a26960b) -- **fix**: [issue #1020](https://github.com/kataras/iris/issues/1020) via [this commit](https://github.com/kataras/iris/commit/3d30ccef05703246b716a14dda14d2f28294dbd2), redis database stores the int as float64, don't change that native behavior, just grab it nicely. - -## Translations (2) - -- [README_PT_BR.md](README_PT_BR.md) for Brazilian Portuguese language via [this PR](https://github.com/kataras/iris/pull/1008) thanks to [@gschri](https://github.com/gschri) -- [README_JPN.md](README_JPN.md) for Japanese language via [this PR](https://github.com/kataras/iris/pull/1015) thanks to [@tkhkokd](https://github.com/tkhkokd). - -Thank you both for your contribution. We all looking forward for the HISTORY translations as well!!! - -# Mo, 21 May 2018 | v10.6.5 - -First of all, special thanks to [@haritsfahreza](https://github.com/haritsfahreza) for translating the entire Iris' README page & Changelogs to the Bahasa Indonesia language via PR: [#1000](https://github.com/kataras/iris/pull/1000)! - -## New Feature: `Execution Rules` - -From the begin of the Iris' journey we used to use the `ctx.Next()` inside handlers in order to call the next handler in the route's registered handlers chain, otherwise the "next handler" would never be executed. - -We could always "force-break" that handlers chain using the `ctx.StopExecution()` to indicate that any future `ctx.Next()` calls will do nothing. - -These things will never change, they were designed in the lower possible level of the Iris' high-performant and unique router and they're working like a charm:) - -We have introduced `Iris MVC Applications` two years later. Iris is the first and the only one Go web framework with a realistic point-view and feature-rich MVC architectural pattern support without sacrifices, always with speed in mind (handlers vs mvc have almost the same speed here!!!). - -A bit later we introduced another two unique features, `Hero Handlers and Service/Dynamic Bindings` (see the very bottom of this HISTORY page). -You loved it, you're using it a lot, just take a look at the recent github issues the community raised about MVC and etc. - -Two recent discussions/support were about calling `Done` handlers inside MVC applications, you could simply do that by implementing the optional `BaseController` as examples shown, i.e: - -```go -func (c *myController) BeginRequest(ctx iris.Context) {} -func (c *myController) EndRequest(ctx iris.Context) { - ctx.Next() // Call of any `Done` handlers. -} -``` - -But for some reason you found that confused. This is where the new feature comes: **The option to change the default behavior of handlers execution's rules PER PARTY**. - -For example, we want to run all handlers(begin, main and done handlers) with the order you register but without the need of the `ctx.Next()` (in that case the only remained way to stop the lifecycle of an http request when next handlers are registered is to use the `ctx.StopExecution()` which, does not allow the next handler(s) to be executed even if `ctx.Next()` called in some place later on, but you're already know this, I hope :)). - -```go -package main - -import ( - "github.com/kataras/iris" - "github.com/kataras/iris/mvc" -) - -func main() { - app := iris.New() - app.Get("/", func(ctx iris.Context) { ctx.Redirect("/example") }) - - m := mvc.New(app.Party("/example")) - - // IMPORTANT - // the new feature, all options can be filled with Force:true, they are all play nice together. - m.Router.SetExecutionRules(iris.ExecutionRules{ - // Begin: <- from `Use[all]` to `Handle[last]` future route handlers, execute all, execute all even if `ctx.Next()` is missing. - // Main: <- all `Handle` future route handlers, execute all >> >>. - Done: iris.ExecutionOptions{Force: true}, // <- from `Handle[last]` to `Done[all]` future route handlers, execute all >> >>. - }) - m.Router.Done(doneHandler) - // m.Router.Done(...) - // ... - // - - m.Handle(&exampleController{}) - - app.Run(iris.Addr(":8080")) -} - -func doneHandler(ctx iris.Context) { - ctx.WriteString("\nFrom Done Handler") -} - -type exampleController struct{} - -func (c *exampleController) Get() string { - return "From Main Handler" - // Note that here we don't binding the `Context`, and we don't call its `Next()` - // function in order to call the `doneHandler`, - // this is done automatically for us because we changed the execution rules with the `SetExecutionRules`. - // - // Therefore, the final output is: - // From Main Handler - // From Done Handler -} -``` - -Example at: [_examples/mvc/middleware/without-ctx-next](_examples/mvc/middleware/without-ctx-next). - -This feature can be applied to any type of application, the example is an MVC Application because many of you asked for this exactly flow the past days. - -## Thank you - -Thank you for your honest support once again, your posts are the heart of this framework. - -Don't forget to [star](https://github.com/kataras/iris/stargazers) the Iris' github repository whenever you can and spread the world about its potentials! - -Be part of this, - -- complete our User Experience Report: https://goo.gl/forms/lnRbVgA6ICTkPyk02 -- join to our Community live chat: https://chat.iris-go.com -- connect to our [new facebook group](https://www.facebook.com/iris.framework) to get notifications about new job opportunities relatively to Iris! - -Sincerely, -[Gerasimos Maropoulos](https://twitter.com/MakisMaropoulos). - -# We, 09 May 2018 | v10.6.4 - -- [fix issue 995](https://github.com/kataras/iris/commit/62457279f41a1f157869a19ef35fb5198694fddb) -- [fix issue 996](https://github.com/kataras/iris/commit/a11bb5619ab6b007dce15da9984a78d88cd38956) - -# We, 02 May 2018 | v10.6.3 - -**Every server should be upgraded to this version**, it contains an important, but easy, fix for the `websocket/Connection#Emit##To`. - -- Websocket: fix https://github.com/kataras/iris/issues/991 - -# Tu, 01 May 2018 | v10.6.2 - -- Websocket: added OnPong to Connection via PR: https://github.com/kataras/iris/pull/988 -- Websocket: `OnError` accepts a `func(error)` now instead of `func(string)`, as requested at: https://github.com/kataras/iris/issues/987 - -# We, 25 April 2018 | v10.6.1 - -- Re-implement the [BoltDB](https://github.com/coreos/bbolt) as built-in back-end storage for sessions(`sessiondb`) using the latest features: [/sessions/sessiondb/boltdb/database.go](sessions/sessiondb/boltdb/database.go), example can be found at [/_examples/sessions/database/boltdb/main.go](_examples/sessions/database/boltdb/main.go). -- Fix a minor issue on [Badger sessiondb example](_examples/sessions/database/badger/main.go). Its `sessions.Config { Expires }` field was `2 *time.Second`, it's `45 *time.Minute` now. -- Other minor improvements to the badger sessiondb. - -# Su, 22 April 2018 | v10.6.0 - -- Fix open redirect by @wozz via PR: https://github.com/kataras/iris/pull/972. -- Fix when destroy session can't remove cookie in subdomain by @Chengyumeng via PR: https://github.com/kataras/iris/pull/964. -- Add `OnDestroy(sid string)` on sessions for registering a listener when a session is destroyed with commit: https://github.com/kataras/iris/commit/d17d7fecbe4937476d00af7fda1c138c1ac6f34d. -- Finally, sessions are in full-sync with the registered database now. That required a lot of internal code changed but **zero code change requirements by your side**. We kept only `badger` and `redis` as the back-end built-in supported sessions storages, they are enough. Made with commit: https://github.com/kataras/iris/commit/f2c3a5f0cef62099fd4d77c5ccb14f654ddbfb5c relative to many issues that you've requested it. - -# Sa, 24 March 2018 | v10.5.0 - -### New - -Add new client cache (helpers) middlewares for even faster static file servers. Read more [there](https://github.com/kataras/iris/pull/935). - -### Breaking Change - -Change the `ValueDefault(, error)` to `ValueDefault(key, defaultValue) ` like `ctx.PostValueIntDefault` or `ctx.Values().GetIntDefault` or `sessions/session#GetIntDefault` or `context#URLParamIntDefault`. -The proposal was made by @jefurry at https://github.com/kataras/iris/issues/937. - -#### How to align your existing codebase - -Just remove the second return value from these calls. - -Nothing too special or hard to change here, think that in our 100+ [_examples](_examples) we had only two of them. - -For example: at [_examples/mvc/basic/main.go line 100](_examples/mvc/basic/main.go#L100) the `count,_ := c.Session.GetIntDefault("count", 1)` **becomes now:** `count := c.Session.GetIntDefault("count", 1)`. - -> Remember that if you can't upgrade then just don't, we dont have any security fixes in this release, but at some point you will have to upgrade for your own good, we always add new features that you will love to embrace! - -# We, 14 March 2018 | v10.4.0 - -- fix `APIBuilder, Party#StaticWeb` and `APIBuilder, Party#StaticEmbedded` wrong strip prefix inside children parties -- keep the `iris, core/router#StaticEmbeddedHandler` and remove the `core/router/APIBuilder#StaticEmbeddedHandler`, (note the `Handler` suffix) it's global and has nothing to do with the `Party` or the `APIBuilder` -- fix high path cleaning between `{}` (we already escape those contents at the [interpreter](macro/interpreter) level but some symbols are still removed by the higher-level api builder) , i.e `\\` from the string's macro function `regex` contents as reported at [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd) -- sync the `golang.org/x/sys/unix` vendor - -## The most important - -We've made static files served up to 8 times faster using the new tool, which is a fork of your beloved `go-bindata`, some unnecessary things for us were removed there and contains some additions for performance boost. - -## Reqs/sec with [shuLhan/go-bindata](https://github.com/shuLhan/go-bindata) and alternatives - -![go-bindata](https://github.com/kataras/bindata/raw/master/go-bindata-benchmark.png) - -## Reqs/sec with [kataras/bindata](https://github.com/kataras/bindata) - -![bindata](https://github.com/kataras/bindata/raw/master/bindata-benchmark.png) - -A **new** function `Party#StaticEmbeddedGzip` which has the same input arguments as the `Party#StaticEmbedded` added. The difference is that the **new** `StaticEmbeddedGzip` accepts the `GzipAsset` and `GzipAssetNames` from the `bindata` (go get -u github.com/kataras/bindata/cmd/bindata). - -You can still use both `bindata` and `go-bindata` tools in the same folder, the first for embedding the rest of the static files (javascript, css, ...) and the second for embedding the templates! - -A full example can be found at: [_examples/file-server/embedding-gziped-files-into-app/main.go](_examples/file-server/embedding-gziped-files-into-app/main.go). - -_Happy Coding!_ - -# Sa, 10 March 2018 | v10.3.0 - -- The only one API Change is the [Application/Context/Router#RouteExists](https://godoc.org/github.com/kataras/iris/core/router#Router.RouteExists), it accepts the `Context` as its first argument instead of last now. - -- Fix cors middleware via https://github.com/iris-contrib/middleware/commit/048e2be034ed172c6754448b8a54a9c55debad46, relative issue: https://github.com/kataras/iris/issues/922 (still pending for a verification). - -- Add `Context#NextOr` and `Context#NextOrNotFound` - -```go -// NextOr checks if chain has a next handler, if so then it executes it -// otherwise it sets a new chain assigned to this Context based on the given handler(s) -// and executes its first handler. -// -// Returns true if next handler exists and executed, otherwise false. -// -// Note that if no next handler found and handlers are missing then -// it sends a Status Not Found (404) to the client and it stops the execution. -NextOr(handlers ...Handler) bool -// NextOrNotFound checks if chain has a next handler, if so then it executes it -// otherwise it sends a Status Not Found (404) to the client and stops the execution. -// -// Returns true if next handler exists and executed, otherwise false. -NextOrNotFound() bool -``` - -- Add a new `Party#AllowMethods` which if called before any `Handle, Get, Post...` will clone the routes to that methods as well. - -- Fix trailing slash from POST method request redirection as reported at: https://github.com/kataras/iris/issues/921 via https://github.com/kataras/iris/commit/dc589d9135295b4d080a9a91e942aacbfe5d56c5 - -- Add examples for read using custom decoder per type, read using custom decoder via `iris#UnmarshalerFunc` and to complete it add an example for the `context#ReadXML`, you can find them [here](https://github.com/kataras/iris/tree/master/_examples#how-to-read-from-contextrequest-httprequest)via https://github.com/kataras/iris/commit/78cd8e5f677fe3ff2c863c5bea7d1c161bf4c31e. - -- Add one more example for custom router macro functions, relative to https://github.com/kataras/iris/issues/918, you can find it [there](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L144-L158), via https://github.com/kataras/iris/commit/a7690c71927cbf3aa876592fab94f04cada91b72 - -- Add wrappers for `Pongo`'s `AsValue()` and `AsSaveValue()` by @neenar via PR: https://github.com/kataras/iris/pull/913 - -- Remove unnecessary reflection usage on `context#UnmarshalBody` via https://github.com/kataras/iris/commit/4b9e41458b62035ea4933789c0a132c3ef2a90cc - - -# Th, 15 February 2018 | v10.2.1 - -Fix subdomains' `StaticEmbedded` & `StaticWeb` not found errors, as reported by [@speedwheel](https://github.com/speedwheel) via [facebook page's chat](https://facebook.com/iris.framework). - -# Th, 08 February 2018 | v10.2.0 - -A new minor version family because it contains a **BREAKING CHANGE** and a new `Party#Reset` function. - -### Party#Done behavior change & new Party#DoneGlobal introduced - -As correctly pointed out by @likakuli at https://github.com/kataras/iris/issues/901, the old `Done` registered -handlers globally instead of party's and its children routes, this was not by accident because `Done` was introduced -before the `UseGlobal` idea and it didn't change for the shake of stability. Now it's time to move on, the new `Done` should be called before the routes that they care about those done handlers and the **new** `DoneGlobal` works like the old `Done`; order doesn't matter and it appends those done handlers -to the current registered routes and the future, globally (to all subdomains, parties every route in the Application). - -The [routing/writing-a-middleware](_examples/routing/writing-a-middleware) examples are updated, read those to understand what's going on, although if you used iris before and you know the vocabulary we use you don't have to, the `DoneGlobal` and `Done` are clearly separated. - -### Party#Reset - -A new `Party#Reset()` function introduced in order to be able to clear parent's Party's begin and done handlers that are registered via `Use` and `Done` at a previous state, nothing crazy about this, it just clears the `middleware` and `doneHandlers` of the current Party instance, see `core/router#APIBuilder` for more. - -### Update your codebase - -Just replace all existing `.Done(` with `.DoneGlobal(` using a rich code editor (like the [VSCode](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)) which supports `find and replace all` and you're ready to Go:) - -# Tu, 06 February 2018 | v10.1.0 - -New Features: - -- Multi-Level subdomain redirect helper, you can find an example [here](https://github.com/kataras/iris/blob/master/_examples/subdomains/redirect/main.go) -- Cache middleware which makes use of the `304` status code, request fires from client to server but server respond with a status code, client is responsible to render the cached, you can find an example [here](https://github.com/kataras/iris/blob/master/_examples/cache/client-side/main.go) -- `websocket/Connection#IsJoined(roomName string)` new method to check if a user is joined to a room. An un-joined connections cannot send messages, this check is optionally. - -More: - -- update vendor/golang/crypto package to its latest version again, they have a lot of fixes there, as you know we're always following the dependencies for any fixes and meanful updates. -- [don't force-set content type on gzip response writer's WriteString and Writef if already there](https://github.com/kataras/iris/commit/af79aad11932f1a4fcbf7ebe28274b96675d0000) -- [new: add websocket/Connection#IsJoined](https://github.com/kataras/iris/commit/cb9e30948c8f1dd099f5168218d110765989992e) -- [fix #897](https://github.com/kataras/iris/commit/21cb572b638e82711910745cfae3c52d836f01f9) -- [add context#StatusCodeNotSuccessful variable for customize even the rfc2616-sec10](https://github.com/kataras/iris/commit/c56b7a3f04d953a264dfff15dadd2b4407d62a6f) -- [fix example comment on routing/dynamic-path/main.go#L101](https://github.com/kataras/iris/commit/0fbf1d45f7893cb1393759b7362444f3d381d182) -- [new: Cache Middleware `iris.Cache304`](https://github.com/kataras/iris/commit/1722355870174cecbc12f7beff8514b058b3b912) -- [fix comment on csrf example](https://github.com/kataras/iris/commit/a39e3d7d6cf528e51e6c7e32a884a8d9f2fadc0b) -- [un-default the Configuration.RemoteAddrHeaders](https://github.com/kataras/iris/commit/47108dc5a147a8b23de61bef86fe9327f0781396) -- [add vscode extension link and badge](https://github.com/kataras/iris/commit/6f594c0a7c641cc98bd683163fffbf5fa5fc8de6) -- [add an `app.View` example for parsing and writing templates outside of the HTTP (similar to context#View)](_examples/view/write-to) -- [new: Support multi-level subdomains redirect](https://github.com/kataras/iris/commit/12d7df113e611a75088c2a72774dab749d2c7685). - -# Tu, 16 January 2018 | v10.0.2 - -## Security | `iris.AutoTLS` - -**Every server should be upgraded to this version**, it contains fixes for the _tls-sni challenge disabled_ some days ago by letsencrypt.org which caused almost every https-enabled golang server to be unable to be functional, therefore support for the _http-01 challenge type_ added. Now the server is testing all available letsencrypt challenges. - -Read more at: - -- https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241 -- https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac - -# Mo, 15 January 2018 | v10.0.1 - -Not any serious problems were found to be resolved here but one, the first one which is important for devs that used the [cache](cache) package. - -- fix a single one cache handler didn't work across multiple route handlers at the same time https://github.com/kataras/iris/pull/852, as reported at https://github.com/kataras/iris/issues/850 -- merge PR https://github.com/kataras/iris/pull/862 -- do not allow concurrent access to the `ExecuteWriter -> Load` when `view#Engine##Reload` was true, as requested at https://github.com/kataras/iris/issues/872 -- badge for open-source projects powered by Iris, learn how to add that badge to your open-source project at [FAQ.md](FAQ.md) file -- upstream update for `golang/crypto` to apply the fix about the [tls-sni challenge disabled](https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241) https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac (**relative to iris.AutoTLS**) - -## New Backers - -1. https://opencollective.com/cetin-basoz - -## New Translations - -1. The Chinese README_ZH.md and HISTORY_ZH.md was translated by @Zeno-Code via https://github.com/kataras/iris/pull/858 -2. New Russian README_RU.md translations by @merrydii via https://github.com/kataras/iris/pull/857 -3. New Greek README_GR.md and HISTORY_GR.md translations via https://github.com/kataras/iris/commit/8c4e17c2a5433c36c148a51a945c4dc35fbe502a#diff-74b06c740d860f847e7b577ad58ddde0 and https://github.com/kataras/iris/commit/bb5a81c540b34eaf5c6c8e993f644a0e66a78fb8 - -## New Examples - -1. [MVC - Register Middleware](_examples/mvc/middleware) - -## New Articles - -1. [A Todo MVC Application using Iris and Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064) -2. [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](bit.ly/2lmKaAZ) - -# Mo, 01 January 2018 | v10.0.0 - -We must thanks [Mrs. Diana](https://www.instagram.com/merry.dii/) for our awesome new [logo](https://iris-go.com/images/icon.svg)! - -You can [contact](mailto:Kovalenkodiana8@gmail.com) her for any design-related enquiries or explore and send a direct message via [instagram](https://www.instagram.com/merry.dii/). - -

- -

- -At this version we have many internal improvements but just two major changes and one big feature, called **hero**. - -> The new version adds 75 plus new commits, the PR is located [here](https://github.com/kataras/iris/pull/849) read the internal changes if you are developing a web framework based on Iris. Why 9 was skipped? Because. - -## Hero - -The new package [hero](hero) contains features for binding any object or function that `handlers` may use, these are called dependencies. Hero funcs can also return any type of values, these values will be dispatched to the client. - -> You may saw binding before but you didn't have code editor's support, with Iris you get truly safe binding thanks to the new `hero` package. It's also fast, near to raw handlers performance because Iris calculates everything before server ran! - -Below you will see some screenshots we prepared for you in order to be easier to understand: - -### 1. Path Parameters - Built-in 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) - -`hero funcs` are very easy to understand and when you start using them **you never go back**. - -Examples: - -- [Basic](_examples/hero/basic/main.go) -- [Overview](_examples/hero/overview) - -## MVC - -You have to understand the `hero` package in order to use the `mvc`, because `mvc` uses the `hero` internally for the controller's methods you use as routes, the same rules applied to those controller's methods of yours as well. - -With this version you can register **any controller's methods as routes manually**, you can **get a route based on a method name and change its `Name` (useful for reverse routing inside templates)**, you can use any **dependencies** registered from `hero.Register` or `mvc.New(iris.Party).Register` per mvc application or per-controller, **you can still use `BeginRequest` and `EndRequest`**, you can catch **`BeforeActivation(b mvc.BeforeActivation)` to add dependencies per controller and `AfterActivation(a mvc.AfterActivation)` to make any post-validations**, **singleton controllers when no dynamic dependencies are used**, **Websocket controller, as simple as a `websocket.Connection` dependency** and more... - -Examples: - -**If you used MVC before then read very carefully: MVC CONTAINS SOME BREAKING CHANGES BUT YOU CAN DO A LOT MORE AND EVEN FASTER THAN BEFORE** - -**PLEASE READ THE EXAMPLES CAREFULLY, WE'VE MADE THEM FOR YOU** - -Old examples are here as well. Compare the two different versions of each example to understand what you win if you upgrade now. - -| NEW | OLD | -| -----------|-------------| -| [Hello world](_examples/mvc/hello-world/main.go) | [OLD Hello world](https://github.com/kataras/iris/blob/v8/_examples/mvc/hello-world/main.go) | -| [Session Controller](_examples/mvc/session-controller/main.go) | [OLD Session Controller](https://github.com/kataras/iris/blob/v8/_examples/mvc/session-controller/main.go) | -| [Overview - Plus Repository and Service layers](_examples/mvc/overview) | [OLD Overview - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/overview) | -| [Login showcase - Plus Repository and Service layers](_examples/mvc/login) | [OLD Login showcase - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/login) | -| [Singleton](_examples/mvc/singleton) | **NEW** | -| [Websocket Controller](_examples/mvc/websocket) | **NEW** | -| [Vue.js Todo MVC](_examples/tutorial/vuejs-todo-mvc) | **NEW** | - -## context#PostMaxMemory - -Remove the old static variable `context.DefaultMaxMemory` and replace it with the configuration `WithPostMaxMemory`. - -```go -// WithPostMaxMemory sets the maximum post data size -// that a client can send to the server, this differs -// from the overral request body size which can be modified -// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`. -// -// Defaults to 32MB or 32 << 20 if you prefer. -func WithPostMaxMemory(limit int64) Configurator -``` - -If you used that old static field you will have to change that single line. - -Usage: - -```go -import "github.com/kataras/iris" - -func main() { - app := iris.New() - // [...] - - app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20)) -} -``` - -## context#UploadFormFiles - -New method to upload multiple files, should be used for common upload actions, it's just a helper function. - -```go -// UploadFormFiles uploads any received file(s) from the client -// to the system physical location "destDirectory". -// -// The second optional argument "before" gives caller the chance to -// modify the *miltipart.FileHeader before saving to the disk, -// it can be used to change a file's name based on the current request, -// all FileHeader's options can be changed. You can ignore it if -// you don't need to use this capability before saving a file to the disk. -// -// Note that it doesn't check if request body streamed. -// -// Returns the copied length as int64 and -// a not nil error if at least one new file -// can't be created due to the operating system's permissions or -// http.ErrMissingFile if no file received. -// -// If you want to receive & accept files and manage them manually you can use the `context#FormFile` -// instead and create a copy function that suits your needs, the below is for generic usage. -// -// The default form's memory maximum size is 32MB, it can be changed by the -// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument. -// -// See `FormFile` to a more controlled to receive a file. -func (ctx *context) UploadFormFiles( - destDirectory string, - before ...func(string, string), - ) (int64, error) -``` - -Example can be found [here](_examples/http_request/upload-files/main.go). - -## context#View - -Just a minor addition, add a second optional variadic argument to the `context#View` method to accept a single value for template binding. -When you just want one value and not key-value pairs, you used to use an empty string on the `ViewData`, which is fine, especially if you preload these from a previous handler/middleware in the request handlers chain. - -```go -func(ctx iris.Context) { - ctx.ViewData("", myItem{Name: "iris" }) - ctx.View("item.html") -} -``` - -Same as: - -```go -func(ctx iris.Context) { - ctx.View("item.html", myItem{Name: "iris" }) -} -``` - -```html -Item's name: {{.Name}} -``` - -## context#YAML - -Add a new `context#YAML` function, it renders a yaml from a structured value. - -```go -// YAML marshals the "v" using the yaml marshaler and renders its result to the client. -func YAML(v interface{}) (int, error) -``` - -## Session#GetString - -`sessions/session#GetString` can now return a filled value even if the stored value is a type of integer, just like the memstore, the context's temp store, the context's path parameters and the context's url parameters. \ No newline at end of file +# Mo, 22 July 2019 | v11.2.0 diff --git a/HISTORY_GR.md b/HISTORY_GR.md index 628a5087..afcbf5e8 100644 --- a/HISTORY_GR.md +++ b/HISTORY_GR.md @@ -11,333 +11,8 @@ ### Πρέπει να αναβαθμίσω το Iris μου; -Οι προγραμματιστές δεν αναγκάζονται να αναβαθμίσουν αν δεν το χρειάζονται πραγματικά. Αναβαθμίστε όποτε αισθάνεστε έτοιμοι. +Οι προγραμματιστές δεν χρειάζεται να αναβαθμίσουν το τοπικό τους Iris αμέσως. Αναβαθμίστε όποτε αισθάνεστε έτοιμοι. -> Το Iris εκμεταλλεύεται τη λεγόμενη λειτουργία [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo). Παίρνετε πλήρως αναπαραγωγίσιμα builds, καθώς αυτή η μέθοδος προστατεύει από τις upstream μετονομασίες και διαγραφές. +**Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `go get github.com/kataras/iris@v11.2.0`. -**Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `go get -u github.com/kataras/iris` ή αφήστε το αυτόματο updater να το κάνει αυτό για σας. - -# Fr, 11 January 2019 | v11.1.1 - -Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-11-january-2019--v1111) για να διαβάσετε στα αγγλικά. - -# Su, 18 November 2018 | v11.1.0 - -Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#su-18-november-2018--v1110) για να διαβάσετε στα αγγλικά για το νέο "versioning" feature. - -# Fr, 09 November 2018 | v11.0.4 - -Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-09-november-2018--v1104) για να διαβάσετε στα αγγλικά τις αλλαγές που φέρνει το τελευταίο patch για την έκδοση 11. - -# Tu, 30 October 2018 | v11.0.2 - -Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-30-october-2018--v1102) για να διαβάσετε στα αγγλικά μια σημαντική διόρθωση για τα x32 machines που φέρνει το τελευταίο patch για την έκδοση 11. - -# Su, 28 October 2018 | v11.0.1 - -Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#su-28-october-2018--v1101) για να διαβάσετε στα αγγλικά τις αλλαγές και το νέο feature που φέρνει το τελευταίο patch για την έκδοση 11. - -# Su, 21 October 2018 | v11.0.0 - -Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#su-21-october-2018--v1100) για να διαβάσετε στα αγγλικά τις αλλαγές και τα νέα features που φέρνει νεότερη έκδοση του Iris, version 11. - -# Sat, 11 August 2018 | v10.7.0 - -Είμαι στην, πραγματικά, ευχάριστη θέση να σας ανακοινώσω το πρώτο στάδιο της σταθερής κυκλοφορίας της έκδοσης **10.7** του Iris Web Framework. - -Η έκδοση 10.7.0 είναι μέρος των [επίσημων διανομών μας](https://github.com/kataras/iris/releases). - -Αυτή η έκδοση δεν περιέχει αλλαγές που μπορούν να αλλάξουν ριζικά τα υπάρχοντα προγράμματα που χτίστηκαν με βάση παλιότερες εκδόσεις του Iris. Οι προγραμματιστές μπορούν να αναβαθμίσουν με απόλυτη ασφάλεια. - -Διαβάστε παρακάτω τις αλλαγές και τις βελτιώσεις στον εσωτερικό άβυσσο του Iris. Επιπλέον έχουμε ακόμα περισσότερα παραδείγματα για αρχάριους στην κοινότητα μας. - -## Νέα παραδείγματα - -- [Iris + WebAssemply = 💓](_examples/webassembly/basic/main.go) **προυποθέτει την έκδοση go11.beta και αφεξ** -- [Server-Sent Events](_examples/http_responsewriter/sse/main.go) -- [Struct Validation on context.ReadJSON](_examples/http_request/read-json-struct-validation/main.go) -- [Extract referrer from "referer" header or URL query parameter](_examples/http_request/extract-referer/main.go) -- [Hero Sessions](_examples/hero/sessions) -- [Yet another dependency injection example with hero](_examples/hero/smart-contract/main.go) -- [Writing an API for the Apache Kafka](_examples/tutorial/api-for-apache-kafka) - -> Επίσης, όλα τα "sessions" παραδείγματα έχουν προσαρμοστεί ώστε να περιέχουν την επιλογή `AllowReclaim: true` - -## kataras/iris/websocket - -- Αλλαγή του "connection list" από απλή λίστα σε `sync.Map`, έγινε με: [αυτό](https://github.com/kataras/iris/commit/5f16704f45bedd767527eadf411cf9bc0f8edaee) και [αυτό το commit](https://github.com/kataras/iris/commit/16b30e8eed1406c61abc01282120870bd9fa31d8) -- Προσθήκη του `iris-ws.js` αρχείου στο διάσημο CDN https://cdnjs.com με [αυτό το PR](https://github.com/kataras/iris/pull/1053) από τον [Dibyendu Das](https://github.com/dibyendu) - -## kataras/iris/core/router - -- Προσθήκη κάποιων `json` field tags και νέα functions όπως τα `ChangeMethod`, `SetStatusOffline` και `RestoreStatus` στη `Route` δομή, προσοχή, για να υσχίσουν αυτών των ειδών οι αλλαγές προυποθέτουν από εσας το κάλεσμα του `Router/Application.RefreshRouter()`. (δεν συνιστάται απόλυτα αλλά είναι χρήσιμο για ειδικά κατασκευασμένες ιστοσελίδες τρίτων που μπορεί να υπάρχουν εκει έξω για διαχείριση ενός Web Server που χτίστηκε με Iris) -- Προσθήκη του `GetRoutesReadOnly` function στην `APIBuilder` δομή - -## kataras/iris/context - -- Προσθήκη των `GetReferrer`, `GetContentTypeRequested` και `URLParamInt32Default` functions -- Εισαγωγή των `Trace`, `Tmpl` και `MainHandlerName` functions στη διεπαφή(interface) `RouteReadOnly` -- Προσθήκη του `OnConnectionClose` function, χρησημοποείται για να καλεί κάποιο function όταν η "underline tcp connection" διακοπεί, εξαιρετικά χρήσιμο για SSE ή και άλλες παρόμοιες υλοποιήσεις μέσα σε έναν Iris Handler -- και του `OnClose` function το οποίο είναι σαν να καλείτε τα `OnConnectionClose(myFunc)` και `defer myFunc()` στον ίδιο Iris Handler [*](https://github.com/kataras/iris/commit/6898c2f755a0e22aa42e3b1799e29c857777a6f9) - -Αυτή η έκδοση περιέχει επίσης κάποιες δευτερεύουσες γραμματικής και τυπογραφικού λάθους διορθώσεις και πιό ευανάγνωστα σχόλια για το [godoc](https://godoc.org/github.com/kataras/iris). - -## Βιομηχανία - -Βρίσκομαι στην ευχάριστη αυτή θέση να σας ανακοινώσω ότι το Iris έχει επιλεγεί ως το κύριο αναπτυξιακό kit(main development kit) για οκτώ μεσαίου ως μεγάλου μεγέθους εταιρείες και μια νέα πολύ ελπιδοφόρα startup με βάση την Ινδία. - -Θέλω να σας ευχαριστήσω όλους, **καθέ μία και έναν ξεχωριστά**, για την αδιάκοπη αυτή υποστήριξη και την εμπιστοσύνη που μου δείξατε όλα αυτά τα χρόνια, ειδικά φέτος, παρά τις φήμες και τις διάφορες δυσφήσεις που είχαμε υποστεί αδίκως από τον ανελέητο ανταγωνισμό. - -# Tu, 05 June 2018 | v10.6.6 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-05-june-2018--v1066) instead. - -# Mo, 21 May 2018 | v10.6.5 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#mo-21-may-2018--v1065) instead. - -# We, 09 May 2018 | v10.6.4 - -- [διόρθωση του bug #995](https://github.com/kataras/iris/commit/62457279f41a1f157869a19ef35fb5198694fddb) -- [διόρθωση του bug #996](https://github.com/kataras/iris/commit/a11bb5619ab6b007dce15da9984a78d88cd38956) - -# We, 02 May 2018 | v10.6.3 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#we-02-may-2018--v1063) instead. - -# Tu, 01 May 2018 | v10.6.2 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-01-may-2018--v1062) instead. - -# We, 25 April 2018 | v10.6.1 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#we-25-april-2018--v1061) instead. - -# Su, 22 April 2018 | v10.6.0 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#su-22-april-2018--v1060) instead. - -# Sa, 24 March 2018 | v10.5.0 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#sa-24-march-2018--v1050) instead. - -# We, 14 March 2018 | v10.4.0 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#we-14-march-2018--v1040) instead. - -# Sa, 10 March 2018 | v10.3.0 - -This history entry is not translated yet to the Greek language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#sa-10-march-2018--v1030) instead. - -# Th, 15 February 2018 | v10.2.1 - -Διόρθωση το οποίο αφορά 404 not found errors στα αρχεία που σερβίρονται από τα `StaticEmbedded` και `StaticWeb` των υποτομεών(subdomains), όπως αναφέρθηκε πριν λίγο από τον [@speedwheel](https://github.com/speedwheel) μέσω [της σελίδας μας στο facebook](https://facebook.com/iris.framework). - -This history entry is not yet translated to Greek. Please read [the english version instead](https://github.com/kataras/iris/blob/master/HISTORY.md#th-15-february-2018--v1021). - -# Th, 08 February 2018 | v10.2.0 - -This history entry is not yet translated to Greek. Please read [the english version instead](https://github.com/kataras/iris/blob/master/HISTORY.md#th-08-february-2018--v1020). - -# Tu, 06 February 2018 | v10.1.0 - -This history entry is not yet translated to Greek. Please read [the english version instead](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-06-february-2018--v1010). - -# Tu, 16 January 2018 | v10.0.2 - -## Ασφάλεια | `iris.AutoTLS` - -**Όλοι οι servers πρέπει να αναβαθμιστούν σε αυτήν την έκδοση**, περιέχει διορθώσεις για το _tls-sni challenge_ το οποίο απενεργοποιήθηκε μερικές μέρες πριν από το letsencrypt.org το οποίο προκάλεσε σχεδόν όλα τα golang https-ενεργποιημένα servers να να μην είναι σε θέση να λειτουργήσουν, έτσι υποστήριξη για το _http-01 challenge_ προστέθηκε σαν αναπλήρωση. Πλέον ο διακομιστής δοκιμάζει όλες τις διαθέσιμες προκλήσεις(challenges) letsencrypt. - -Διαβάστε περισσότερα: - -- https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241 -- https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac - -# Mo, 15 January 2018 | v10.0.1 - -- διόρθωση του cache handler που δεν δούλευε όπως έπρεπε όταν γινόταν εγγραφή σε πάνω από ένα handler, παλιότερα ήταν ένα cache handler προς ένα route handler, τώρα το ίδιο handler μπορεί να καταχωρηθεί σε όσα route handlers θέλετε https://github.com/kataras/iris/pull/852, όπως είχε αναφερθεί στο https://github.com/kataras/iris/issues/850 -- συγχώνευση PR https://github.com/kataras/iris/pull/862 -- απαγόρευση της ταυτόχρονης προσπέλασης του `ExecuteWriter -> Load` όταν το `view#Engine##Reload` είναι true, όπως είχε ζητηθεί στο https://github.com/kataras/iris/issues/872 -- αναβάθμιση του ενσωματωμένου πακέτου `golang/crypto` για να εφαρμοστεί η επιδιόρθωση για το [tls-sni challenge disabled](https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241) https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac (**σχετικό με το iris.AutoTLS**) - -## Νέοι Υποστηρικτές - -1. https://opencollective.com/cetin-basoz - -## Νέες Μεταφράσεις - -1. Aναβαθμίσεις για την Κινέζικη μετάφραση README_ZH.md (νέο) και HISTORY_ZH.md από @Zeno-Code μέσω του https://github.com/kataras/iris/pull/858 -2. Το Ρώσικο README_RU.md μεταφράστηκε από την @merrydii μέσω του https://github.com/kataras/iris/pull/857 -3. Τα Ελληνικά README_GR.md και HISTORY_GR.md μεταφράστηκαν μέσω των https://github.com/kataras/iris/commit/8c4e17c2a5433c36c148a51a945c4dc35fbe502a#diff-74b06c740d860f847e7b577ad58ddde0 και https://github.com/kataras/iris/commit/bb5a81c540b34eaf5c6c8e993f644a0e66a78fb8 - -## Νέα Παραδείγματα - -1. [MVC - Register Middleware](_examples/mvc/middleware) - -## Νέα Άρθρα - -1. [A Todo MVC Application using Iris and Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064) -2. [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](bit.ly/2lmKaAZ) - -# Mo, 01 January 2018 | v10.0.0 - -Πρέπει να ευχαριστήσουμε την [Κυρία Diana](https://www.instagram.com/merry.dii/) για το νέο μας [λογότυπο](https://iris-go.com/images/icon.svg)! - -Μπορείτε να [επικοινωνήσετε](mailto:Kovalenkodiana8@gmail.com) μαζί της για οποιεσδήποτε σχετικές με το σχεδιασμό εργασίες ή να της στείλειτε ένα άμεσο μήνυμα μέσω [instagram](https://www.instagram.com/merry.dii/). - -

- -

- -Σε αυτή την έκδοση έχουμε πολλές εσωτερικές βελτιώσεις αλλά μόνο δύο μεγάλες αλλαγές και ένα μεγάλο χαρακτηριστικό, που ονομάζεται **hero**. - -> Η νέα έκδοση προσθέτει 75 καινούρια commits, το PR βρίσκεται [εδώ](https://github.com/kataras/iris/pull/849). Παρακαλώ διαβάστε τις εσωτερικές αλλαγές αν σχεδιάζετε ένα web framework που βασίζεται στο Iris. Γιατί η έκδοση 9 παραλείφθηκε; Έτσι. - -## Hero - -Το νέο πακέτο [hero](hero) περιέχει χαρακτηριστικά για σύνδεση(binding) οποιουδήποτε αντικειμένου ή function το οποίο τα `handlers` μπορεί να χρησημοποιούν, αυτά λεγόνται εξαρτήσεις(dependencies). Τα Hero funcs μπορούν επίσης να επιστρέψουν οποιαδήποτε τιμή, οποιουδήποτε τύπου, αυτές οι τιμές αποστέλλονται στον πελάτη(client). - -> Μπορεί να είχατε ξαναδει "εξαρτήσεις" και "δέσιμο" πριν αλλά ποτέ με υποστήριξη από τον επεξεργαστή κώδικα (code editor), με το Iris πέρνεις πραγματικά ασφαλή "δεσίματα"(bindings) χάρη στο νέο `hero` πακέτο. Αυτή η όλη εκτέλεση(implementation) είναι επίσης η ποιο γρήγορη που έχει επιτευχθεί εως τώρα, η επίδοση είναι πολύ κοντά στα απλά "handlers" και αυτό γιατί το Iris υπολογίζει τα πάντα πριν καν ο server τρέξει! - -Παρακάτω θα δείτε μερικά στιγμιότυπα που ετοιμάσαμε για εσάς, ώστε να γίνουν πιο κατανοητά τα παραπάνω: - -### 1. Παράμετροι διαδρομής - Ενσωματωμένες Εξαρτήσεις (Built-in Dependencies) - -![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png) - -### 2. Υπηρεσίες - Στατικές Eξαρτήσεις (Static Dependencies) - -![](https://github.com/kataras/explore/raw/master/iris/hero/hero-2-monokai.png) - -### 3. Ανά Αίτηση - Δυναμικές Eξαρτήσεις (Dynamic Dependencies) - -![](https://github.com/kataras/explore/raw/master/iris/hero/hero-3-monokai.png) - -Είναι πραγματικά πολύ εύκολο να καταλάβεις πως δουλεύουν τα `hero funcs` και όταν αρχίσεις να τα χρησιμοποιείς **δεν γυρίζεις ποτέ πίσω**. - -Παραδείγματα: - -- [Βασικό](_examples/hero/basic/main.go) -- [Επισκόπηση](_examples/hero/overview) - -## MVC - -Πρέπει να καταλάβεις πως δουλεύει το `hero` πακετό ώστε να να δουλέψεις με το `mvc`, γιατί το `mvc` πακέτο βασίζετε στο `hero` για τις μεθόδους του controller σου, οι ίδιοι κανόνες εφαρμόζονται και εκεί. - -Παραδείγματα: - -**Αν χρησημοποιούσατε το MVC πριν, διαβάστε προσεχτικά: Το MVC ΠΕΡΙΕΧΕΙ ΟΡΙΣΜΕΝΕΣ ΑΛΛΑΓΕΣ, ΜΠΟΡΕΙΤΕ ΝΑ ΚΑΝΕΤΕ ΠΕΡΙΣΣΟΤΕΡΑ ΑΠΟ'ΤΙ ΠΡΙΝ** - -**ΠΑΡΑΚΑΛΩ ΔΙΑΒΑΣΤΕ ΤΑ ΠΑΡΑΔΕΙΓΜΑΤΑ ΠΡΟΣΕΧΤΙΚΑ, ΓΙΑ ΕΣΑΣ ΦΤΙΑΧΤΗΚΑΝ** - -Τα παλιά παραδείγματα είναι επίσης εδώ ώστε να μπορείτε να τα συγκρίνετε με τα καινούρια. - -| ΤΩΡΑ | ΠΡΙΝ | -| -----------|-------------| -| [Hello world](_examples/mvc/hello-world/main.go) | [ΠΑΛΙΟ Hello world](https://github.com/kataras/iris/blob/v8/_examples/mvc/hello-world/main.go) | -| [Session Controller](_examples/mvc/session-controller/main.go) | [ΠΑΛΙΟ Session Controller](https://github.com/kataras/iris/blob/v8/_examples/mvc/session-controller/main.go) | -| [Overview - Plus Repository and Service layers](_examples/mvc/overview) | [ΠΑΛΙΟ Overview - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/overview) | -| [Login showcase - Plus Repository and Service layers](_examples/mvc/login) | [ΠΑΛΙΟ Login showcase - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/login) | -| [Singleton](_examples/mvc/singleton) | **NEO** | -| [Websocket Controller](_examples/mvc/websocket) | **NEO** | -| [Vue.js Todo MVC](_examples/tutorial/vuejs-todo-mvc) | **NEO** | - -## context#PostMaxMemory - -Αφαίρεση της παλιάς στατικής μεταβλητής `context.DefaultMaxMemory` και αντικατάσταση με ρύθμιση στο configuration `WithPostMaxMemory`. - -```go -// WithPostMaxMemory sets the maximum post data size -// that a client can send to the server, this differs -// from the overral request body size which can be modified -// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`. -// -// Defaults to 32MB or 32 << 20 if you prefer. -func WithPostMaxMemory(limit int64) Configurator -``` - -Αν χρησημοποιούσατε την παλιά στατική μεταβλητή θα χρειαστεί να κάνετε μια αλλαγή σε εκείνη τη γραμμή του κώδικα. - -```go -import "github.com/kataras/iris" - -func main() { - app := iris.New() - // [...] - - app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20)) -} -``` - -## context#UploadFormFiles - -Νέα μέθοδος για ανέβασμα πολλαπλών αρχείων από τον client, πρέπει να χρησημοποιείται για απλές και συνηθισμένες καταστάσεις, ένα helper είναι μόνο. - -```go -// UploadFormFiles uploads any received file(s) from the client -// to the system physical location "destDirectory". -// -// The second optional argument "before" gives caller the chance to -// modify the *miltipart.FileHeader before saving to the disk, -// it can be used to change a file's name based on the current request, -// all FileHeader's options can be changed. You can ignore it if -// you don't need to use this capability before saving a file to the disk. -// -// Note that it doesn't check if request body streamed. -// -// Returns the copied length as int64 and -// a not nil error if at least one new file -// can't be created due to the operating system's permissions or -// http.ErrMissingFile if no file received. -// -// If you want to receive & accept files and manage them manually you can use the `context#FormFile` -// instead and create a copy function that suits your needs, the below is for generic usage. -// -// The default form's memory maximum size is 32MB, it can be changed by the -// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument. -// -// See `FormFile` to a more controlled to receive a file. -func (ctx *context) UploadFormFiles( - destDirectory string, - before ...func(string, string), - ) (int64, error) -``` - -Το παράδειγμα μπορεί να βρεθεί [εδώ](_examples/http_request/upload-files/main.go). - -## context#View - -Απλά μια μικρή προσθήκη μια δεύτερης προαιρετικής variadic παράμετρου στη `context#View` μέθοδο για να δέχεται μια μονή τιμή για template binding. -Όταν απλά θέλετε να εμφάνισετε ένα struct value και όχι ζεύγη από κλειδί-τιμή, παλιότερα για να το κάνετε αυτό έπρεπε να δηλώσετε κενό string στη 1η παράμετρο στη `context#ViewData` μέθοδο, το οποίο είναι μια χαρά ειδικά αν δηλώνατε αυτά τα δεδομένα σε προηγούμενο handler της αλυσίδας. - -```go -func(ctx iris.Context) { - ctx.ViewData("", myItem{Name: "iris" }) - ctx.View("item.html") -} -``` - -Το ίδιο όπως: - -```go -func(ctx iris.Context) { - ctx.View("item.html", myItem{Name: "iris" }) -} -``` - -```html -Item's name: {{.Name}} -``` - -## context#YAML - -Προσθήκη νέας μεθόδου, `context#YAML`, εμφανίζει δομημένο yaml κείμενο από struct value. - -```go -// YAML marshals the "v" using the yaml marshaler and renders its result to the client. -func YAML(v interface{}) (int, error) -``` - -## Session#GetString - -Η μέθοδος `sessions/session#GetString` μπορεί πλέον να επιστρέψει τιμή ακόμα και απο τιμή που αποθηκεύτηκαι σαν αριθμός (integer), όπως ακριβώς κάνουν ήδη τα: memstore, η προσωρινή μνήμη του context, οι δυναμικές μεταβλητές του path routing και οι παράμετροι του url query. \ No newline at end of file +# Mo, 22 July 2019 | v11.2.0 diff --git a/HISTORY_ID.md b/HISTORY_ID.md index b37c2d09..d82750b2 100644 --- a/HISTORY_ID.md +++ b/HISTORY_ID.md @@ -13,412 +13,6 @@ Developers tidak diwajibkan untuk melakukan upgrade apabila mereka tidak membutuhkannya. Anda bisa melakukan upgrade ketika anda sudah siap. -> Iris menggunakan fitur [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo). Anda mendapatkan build yang benar - benar dapat direproduksi, karena metode ini menjaga terhadap penggantian nama dan penghapusan di upstream. +**Cara Upgrade**: Bukan command-line anda dan eksekuis perintah ini: `go get github.com/kataras/iris@v11.2.0`. -**Cara Upgrade**: Bukan command-line anda dan eksekuis perintah ini: `go get -u github.com/kataras/iris` atau biarkan updater otomatis melakukannya untuk anda. - -# Fr, 11 January 2019 | v11.1.1 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-11-january-2019--v1111) instead. - -# Su, 18 November 2018 | v11.1.0 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#su-18-november-2018--v1110) instead. - -# Fr, 09 November 2018 | v11.0.4 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-09-november-2018--v1104) instead. - -# Tu, 30 October 2018 | v11.0.2 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-30-october-2018--v1102) instead. - -# Su, 28 October 2018 | v11.0.1 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#su-28-october-2018--v1101) instead. - -# Su, 21 October 2018 | v11.0.0 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#su-21-october-2018--v1100) instead. - -# Sat, 11 August 2018 | v10.7.0 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#sat-11-august-2018--v1070) instead. - -# Tu, 05 June 2018 | v10.6.6 - -This history entry is not translated yet to the Indonesian language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-05-june-2018--v1066) instead. - -# Mo, 21 May 2018 | v10.6.5 - -This history entry is not translated yet to the Bahasa Indonesia language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#mo-21-may-2018--v1065) instead. - -# We, 09 May 2018 | v10.6.4 - -- [fix issue 995](https://github.com/kataras/iris/commit/62457279f41a1f157869a19ef35fb5198694fddb) -- [fix issue 996](https://github.com/kataras/iris/commit/a11bb5619ab6b007dce15da9984a78d88cd38956) - -# We, 02 May 2018 | v10.6.3 - -**Every server should be upgraded to this version**, it contains an important, but easy, fix for the `websocket/Connection#Emit##To`. - -- Websocket: fix https://github.com/kataras/iris/issues/991 - -# Tu, 01 May 2018 | v10.6.2 - -- Websocket: added OnPong to Connection via PR: https://github.com/kataras/iris/pull/988 -- Websocket: `OnError` accepts a `func(error)` now instead of `func(string)`, as requested at: https://github.com/kataras/iris/issues/987 - -# We, 25 April 2018 | v10.6.1 - -- Re-implement the [BoltDB](https://github.com/coreos/bbolt) as built-in back-end storage for sessions(`sessiondb`) using the latest features: [/sessions/sessiondb/boltdb/database.go](sessions/sessiondb/boltdb/database.go), example can be found at [/_examples/sessions/database/boltdb/main.go](_examples/sessions/database/boltdb/main.go). -- Fix a minor issue on [Badger sessiondb example](_examples/sessions/database/badger/main.go). Its `sessions.Config { Expires }` field was `2 *time.Second`, it's `45 *time.Minute` now. -- Other minor improvements to the badger sessiondb. - -# Su, 22 April 2018 | v10.6.0 - -- Fix open redirect by @wozz via PR: https://github.com/kataras/iris/pull/972. -- Fix when destroy session can't remove cookie in subdomain by @Chengyumeng via PR: https://github.com/kataras/iris/pull/964. -- Add `OnDestroy(sid string)` on sessions for registering a listener when a session is destroyed with commit: https://github.com/kataras/iris/commit/d17d7fecbe4937476d00af7fda1c138c1ac6f34d. -- Finally, sessions are in full-sync with the registered database now. That required a lot of internal code changed but **zero code change requirements by your side**. We kept only `badger` and `redis` as the back-end built-in supported sessions storages, they are enough. Made with commit: https://github.com/kataras/iris/commit/f2c3a5f0cef62099fd4d77c5ccb14f654ddbfb5c relative to many issues that you've requested it. - -# Sa, 24 March 2018 | v10.5.0 - -### New - -Add new client cache (helpers) middlewares for even faster static file servers. Read more [there](https://github.com/kataras/iris/pull/935). - -### Breaking Change - -Change the `ValueDefault(, error)` to `ValueDefault(key, defaultValue) ` like `ctx.PostValueIntDefault` or `ctx.Values().GetIntDefault` or `sessions/session#GetIntDefault` or `context#URLParamIntDefault`. -The proposal was made by @jefurry at https://github.com/kataras/iris/issues/937. - -#### How to align your existing codebase - -Just remove the second return value from these calls. - -Nothing too special or hard to change here, think that in our 100+ [_examples](_examples) we had only two of them. - -For example: at [_examples/mvc/basic/main.go line 100](_examples/mvc/basic/main.go#L100) the `count,_ := c.Session.GetIntDefault("count", 1)` **becomes now:** `count := c.Session.GetIntDefault("count", 1)`. - -> Remember that if you can't upgrade then just don't, we dont have any security fixes in this release, but at some point you will have to upgrade for your own good, we always add new features that you will love to embrace! - -# We, 14 March 2018 | v10.4.0 - -- fix `APIBuilder, Party#StaticWeb` and `APIBuilder, Party#StaticEmbedded` wrong strip prefix inside children parties -- keep the `iris, core/router#StaticEmbeddedHandler` and remove the `core/router/APIBuilder#StaticEmbeddedHandler`, (note the `Handler` suffix) it's global and has nothing to do with the `Party` or the `APIBuilder` -- fix high path cleaning between `{}` (we already escape those contents at the [interpreter](macro/interpreter) level but some symbols are still removed by the higher-level api builder) , i.e `\\` from the string's macro function `regex` contents as reported at [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd) -- sync the `golang.org/x/sys/unix` vendor - -## The most important - -We've made static files served up to 8 times faster using the new tool, which is a fork of your beloved `go-bindata`, some unnecessary things for us were removed there and contains some additions for performance boost. - -## Reqs/sec with [shuLhan/go-bindata](https://github.com/shuLhan/go-bindata) and alternatives - -![go-bindata](https://github.com/kataras/bindata/raw/master/go-bindata-benchmark.png) - -## Reqs/sec with [kataras/bindata](https://github.com/kataras/bindata) - -![bindata](https://github.com/kataras/bindata/raw/master/bindata-benchmark.png) - -A **new** function `Party#StaticEmbeddedGzip` which has the same input arguments as the `Party#StaticEmbedded` added. The difference is that the **new** `StaticEmbeddedGzip` accepts the `GzipAsset` and `GzipAssetNames` from the `bindata` (go get -u github.com/kataras/bindata/cmd/bindata). - -You can still use both `bindata` and `go-bindata` tools in the same folder, the first for embedding the rest of the static files (javascript, css, ...) and the second for embedding the templates! - -A full example can be found at: [_examples/file-server/embedding-gziped-files-into-app/main.go](_examples/file-server/embedding-gziped-files-into-app/main.go). - -_Happy Coding!_ - -# Sa, 10 March 2018 | v10.3.0 - -- The only one API Change is the [Application/Context/Router#RouteExists](https://godoc.org/github.com/kataras/iris/core/router#Router.RouteExists), it accepts the `Context` as its first argument instead of last now. - -- Fix cors middleware via https://github.com/iris-contrib/middleware/commit/048e2be034ed172c6754448b8a54a9c55debad46, relative issue: https://github.com/kataras/iris/issues/922 (still pending for a verification). - -- Add `Context#NextOr` and `Context#NextOrNotFound` - -```go -// NextOr checks if chain has a next handler, if so then it executes it -// otherwise it sets a new chain assigned to this Context based on the given handler(s) -// and executes its first handler. -// -// Returns true if next handler exists and executed, otherwise false. -// -// Note that if no next handler found and handlers are missing then -// it sends a Status Not Found (404) to the client and it stops the execution. -NextOr(handlers ...Handler) bool -// NextOrNotFound checks if chain has a next handler, if so then it executes it -// otherwise it sends a Status Not Found (404) to the client and stops the execution. -// -// Returns true if next handler exists and executed, otherwise false. -NextOrNotFound() bool -``` - -- Add a new `Party#AllowMethods` which if called before any `Handle, Get, Post...` will clone the routes to that methods as well. - -- Fix trailing slash from POST method request redirection as reported at: https://github.com/kataras/iris/issues/921 via https://github.com/kataras/iris/commit/dc589d9135295b4d080a9a91e942aacbfe5d56c5 - -- Add examples for read using custom decoder per type, read using custom decoder via `iris#UnmarshalerFunc` and to complete it add an example for the `context#ReadXML`, you can find them [here](https://github.com/kataras/iris/tree/master/_examples#how-to-read-from-contextrequest-httprequest)via https://github.com/kataras/iris/commit/78cd8e5f677fe3ff2c863c5bea7d1c161bf4c31e. - -- Add one more example for custom router macro functions, relative to https://github.com/kataras/iris/issues/918, you can find it [there](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L144-L158), via https://github.com/kataras/iris/commit/a7690c71927cbf3aa876592fab94f04cada91b72 - -- Add wrappers for `Pongo`'s `AsValue()` and `AsSaveValue()` by @neenar via PR: https://github.com/kataras/iris/pull/913 - -- Remove unnecessary reflection usage on `context#UnmarshalBody` via https://github.com/kataras/iris/commit/4b9e41458b62035ea4933789c0a132c3ef2a90cc - - -# Th, 15 February 2018 | v10.2.1 - -Fix subdomains' `StaticEmbedded` & `StaticWeb` not found errors, as reported by [@speedwheel](https://github.com/speedwheel) via [facebook page's chat](https://facebook.com/iris.framework). - -# Th, 08 February 2018 | v10.2.0 - -A new minor version family because it contains a **BREAKING CHANGE** and a new `Party#Reset` function. - -### Party#Done behavior change & new Party#DoneGlobal introduced - -As correctly pointed out by @likakuli at https://github.com/kataras/iris/issues/901, the old `Done` registered -handlers globally instead of party's and its children routes, this was not by accident because `Done` was introduced -before the `UseGlobal` idea and it didn't change for the shake of stability. Now it's time to move on, the new `Done` should be called before the routes that they care about those done handlers and the **new** `DoneGlobal` works like the old `Done`; order doesn't matter and it appends those done handlers -to the current registered routes and the future, globally (to all subdomains, parties every route in the Application). - -The [routing/writing-a-middleware](_examples/routing/writing-a-middleware) examples are updated, read those to understand what's going on, although if you used iris before and you know the vocabulary we use you don't have to, the `DoneGlobal` and `Done` are clearly separated. - -### Party#Reset - -A new `Party#Reset()` function introduced in order to be able to clear parent's Party's begin and done handlers that are registered via `Use` and `Done` at a previous state, nothing crazy about this, it just clears the `middleware` and `doneHandlers` of the current Party instance, see `core/router#APIBuilder` for more. - -### Update your codebase - -Just replace all existing `.Done(` with `.DoneGlobal(` using a rich code editor (like the [VSCode](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)) which supports `find and replace all` and you're ready to Go:) - -# Tu, 06 February 2018 | v10.1.0 - -New Features: - -- Multi-Level subdomain redirect helper, you can find an example [here](https://github.com/kataras/iris/blob/master/_examples/subdomains/redirect/main.go) -- Cache middleware which makes use of the `304` status code, request fires from client to server but server respond with a status code, client is responsible to render the cached, you can find an example [here](https://github.com/kataras/iris/blob/master/_examples/cache/client-side/main.go) -- `websocket/Connection#IsJoined(roomName string)` new method to check if a user is joined to a room. An un-joined connections cannot send messages, this check is optionally. - -More: - -- update vendor/golang/crypto package to its latest version again, they have a lot of fixes there, as you know we're always following the dependencies for any fixes and meanful updates. -- [don't force-set content type on gzip response writer's WriteString and Writef if already there](https://github.com/kataras/iris/commit/af79aad11932f1a4fcbf7ebe28274b96675d0000) -- [new: add websocket/Connection#IsJoined](https://github.com/kataras/iris/commit/cb9e30948c8f1dd099f5168218d110765989992e) -- [fix #897](https://github.com/kataras/iris/commit/21cb572b638e82711910745cfae3c52d836f01f9) -- [add context#StatusCodeNotSuccessful variable for customize even the rfc2616-sec10](https://github.com/kataras/iris/commit/c56b7a3f04d953a264dfff15dadd2b4407d62a6f) -- [fix example comment on routing/dynamic-path/main.go#L101](https://github.com/kataras/iris/commit/0fbf1d45f7893cb1393759b7362444f3d381d182) -- [new: Cache Middleware `iris.Cache304`](https://github.com/kataras/iris/commit/1722355870174cecbc12f7beff8514b058b3b912) -- [fix comment on csrf example](https://github.com/kataras/iris/commit/a39e3d7d6cf528e51e6c7e32a884a8d9f2fadc0b) -- [un-default the Configuration.RemoteAddrHeaders](https://github.com/kataras/iris/commit/47108dc5a147a8b23de61bef86fe9327f0781396) -- [add vscode extension link and badge](https://github.com/kataras/iris/commit/6f594c0a7c641cc98bd683163fffbf5fa5fc8de6) -- [add an `app.View` example for parsing and writing templates outside of the HTTP (similar to context#View)](_examples/view/write-to) -- [new: Support multi-level subdomains redirect](https://github.com/kataras/iris/commit/12d7df113e611a75088c2a72774dab749d2c7685). - -# Tu, 16 January 2018 | v10.0.2 - -## Security | `iris.AutoTLS` - -**Every server should be upgraded to this version**, it contains fixes for the _tls-sni challenge disabled_ some days ago by letsencrypt.org which caused almost every https-enabled golang server to be unable to be functional, therefore support for the _http-01 challenge type_ added. Now the server is testing all available letsencrypt challenges. - -Read more at: - -- https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241 -- https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac - -# Mo, 15 January 2018 | v10.0.1 - -Not any serious problems were found to be resolved here but one, the first one which is important for devs that used the [cache](cache) package. - -- fix a single one cache handler didn't work across multiple route handlers at the same time https://github.com/kataras/iris/pull/852, as reported at https://github.com/kataras/iris/issues/850 -- merge PR https://github.com/kataras/iris/pull/862 -- do not allow concurrent access to the `ExecuteWriter -> Load` when `view#Engine##Reload` was true, as requested at https://github.com/kataras/iris/issues/872 -- badge for open-source projects powered by Iris, learn how to add that badge to your open-source project at [FAQ.md](FAQ.md) file -- upstream update for `golang/crypto` to apply the fix about the [tls-sni challenge disabled](https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241) https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac (**relative to iris.AutoTLS**) - -## New Backers - -1. https://opencollective.com/cetin-basoz - -## New Translations - -1. The Chinese README_ZH.md and HISTORY_ZH.md was translated by @Zeno-Code via https://github.com/kataras/iris/pull/858 -2. New Russian README_RU.md translations by @merrydii via https://github.com/kataras/iris/pull/857 -3. New Greek README_GR.md and HISTORY_GR.md translations via https://github.com/kataras/iris/commit/8c4e17c2a5433c36c148a51a945c4dc35fbe502a#diff-74b06c740d860f847e7b577ad58ddde0 and https://github.com/kataras/iris/commit/bb5a81c540b34eaf5c6c8e993f644a0e66a78fb8 - -## New Examples - -1. [MVC - Register Middleware](_examples/mvc/middleware) - -## New Articles - -1. [A Todo MVC Application using Iris and Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064) -2. [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](bit.ly/2lmKaAZ) - -# Mo, 01 January 2018 | v10.0.0 - -We must thanks [Mrs. Diana](https://www.instagram.com/merry.dii/) for our awesome new [logo](https://iris-go.com/images/icon.svg)! - -You can [contact](mailto:Kovalenkodiana8@gmail.com) her for any design-related enquiries or explore and send a direct message via [instagram](https://www.instagram.com/merry.dii/). - -

- -

- -At this version we have many internal improvements but just two major changes and one big feature, called **hero**. - -> The new version adds 75 plus new commits, the PR is located [here](https://github.com/kataras/iris/pull/849) read the internal changes if you are developing a web framework based on Iris. Why 9 was skipped? Because. - -## Hero - -The new package [hero](hero) contains features for binding any object or function that `handlers` may use, these are called dependencies. Hero funcs can also return any type of values, these values will be dispatched to the client. - -> You may saw binding before but you didn't have code editor's support, with Iris you get truly safe binding thanks to the new `hero` package. It's also fast, near to raw handlers performance because Iris calculates everything before server ran! - -Below you will see some screenshots we prepared for you in order to be easier to understand: - -### 1. Path Parameters - Built-in 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) - -`hero funcs` are very easy to understand and when you start using them **you never go back**. - -Examples: - -- [Basic](_examples/hero/basic/main.go) -- [Overview](_examples/hero/overview) - -## MVC - -You have to understand the `hero` package in order to use the `mvc`, because `mvc` uses the `hero` internally for the controller's methods you use as routes, the same rules applied to those controller's methods of yours as well. - -With this version you can register **any controller's methods as routes manually**, you can **get a route based on a method name and change its `Name` (useful for reverse routing inside templates)**, you can use any **dependencies** registered from `hero.Register` or `mvc.New(iris.Party).Register` per mvc application or per-controller, **you can still use `BeginRequest` and `EndRequest`**, you can catch **`BeforeActivation(b mvc.BeforeActivation)` to add dependencies per controller and `AfterActivation(a mvc.AfterActivation)` to make any post-validations**, **singleton controllers when no dynamic dependencies are used**, **Websocket controller, as simple as a `websocket.Connection` dependency** and more... - -Examples: - -**If you used MVC before then read very carefully: MVC CONTAINS SOME BREAKING CHANGES BUT YOU CAN DO A LOT MORE AND EVEN FASTER THAN BEFORE** - -**PLEASE READ THE EXAMPLES CAREFULLY, WE'VE MADE THEM FOR YOU** - -Old examples are here as well. Compare the two different versions of each example to understand what you win if you upgrade now. - -| NEW | OLD | -| -----------|-------------| -| [Hello world](_examples/mvc/hello-world/main.go) | [OLD Hello world](https://github.com/kataras/iris/blob/v8/_examples/mvc/hello-world/main.go) | -| [Session Controller](_examples/mvc/session-controller/main.go) | [OLD Session Controller](https://github.com/kataras/iris/blob/v8/_examples/mvc/session-controller/main.go) | -| [Overview - Plus Repository and Service layers](_examples/mvc/overview) | [OLD Overview - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/overview) | -| [Login showcase - Plus Repository and Service layers](_examples/mvc/login) | [OLD Login showcase - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/login) | -| [Singleton](_examples/mvc/singleton) | **NEW** | -| [Websocket Controller](_examples/mvc/websocket) | **NEW** | -| [Vue.js Todo MVC](_examples/tutorial/vuejs-todo-mvc) | **NEW** | - -## context#PostMaxMemory - -Remove the old static variable `context.DefaultMaxMemory` and replace it with the configuration `WithPostMaxMemory`. - -```go -// WithPostMaxMemory sets the maximum post data size -// that a client can send to the server, this differs -// from the overral request body size which can be modified -// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`. -// -// Defaults to 32MB or 32 << 20 if you prefer. -func WithPostMaxMemory(limit int64) Configurator -``` - -If you used that old static field you will have to change that single line. - -Usage: - -```go -import "github.com/kataras/iris" - -func main() { - app := iris.New() - // [...] - - app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20)) -} -``` - -## context#UploadFormFiles - -New method to upload multiple files, should be used for common upload actions, it's just a helper function. - -```go -// UploadFormFiles uploads any received file(s) from the client -// to the system physical location "destDirectory". -// -// The second optional argument "before" gives caller the chance to -// modify the *miltipart.FileHeader before saving to the disk, -// it can be used to change a file's name based on the current request, -// all FileHeader's options can be changed. You can ignore it if -// you don't need to use this capability before saving a file to the disk. -// -// Note that it doesn't check if request body streamed. -// -// Returns the copied length as int64 and -// a not nil error if at least one new file -// can't be created due to the operating system's permissions or -// http.ErrMissingFile if no file received. -// -// If you want to receive & accept files and manage them manually you can use the `context#FormFile` -// instead and create a copy function that suits your needs, the below is for generic usage. -// -// The default form's memory maximum size is 32MB, it can be changed by the -// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument. -// -// See `FormFile` to a more controlled to receive a file. -func (ctx *context) UploadFormFiles( - destDirectory string, - before ...func(string, string), - ) (int64, error) -``` - -Example can be found [here](_examples/http_request/upload-files/main.go). - -## context#View - -Just a minor addition, add a second optional variadic argument to the `context#View` method to accept a single value for template binding. -When you just want one value and not key-value pairs, you used to use an empty string on the `ViewData`, which is fine, especially if you preload these from a previous handler/middleware in the request handlers chain. - -```go -func(ctx iris.Context) { - ctx.ViewData("", myItem{Name: "iris" }) - ctx.View("item.html") -} -``` - -Same as: - -```go -func(ctx iris.Context) { - ctx.View("item.html", myItem{Name: "iris" }) -} -``` - -```html -Item's name: {{.Name}} -``` - -## context#YAML - -Add a new `context#YAML` function, it renders a yaml from a structured value. - -```go -// YAML marshals the "v" using the yaml marshaler and renders its result to the client. -func YAML(v interface{}) (int, error) -``` - -## Session#GetString - -`sessions/session#GetString` can now return a filled value even if the stored value is a type of integer, just like the memstore, the context's temp store, the context's path parameters and the context's url parameters. \ No newline at end of file +# Mo, 22 July 2019 | v11.2.0 diff --git a/HISTORY_ZH.md b/HISTORY_ZH.md index d66a4fcc..b24d7771 100644 --- a/HISTORY_ZH.md +++ b/HISTORY_ZH.md @@ -13,400 +13,6 @@ 如果没有必要,不会强制升级。如果你已经准备好了,可以随时升级。 -> Iris 使用 Golang 的 [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) 特性, 避免依赖包的更改带来影响。 +**如何升级**: 打开命令行执行以下命令: `go get github.com/kataras/iris@v11.2.0`. -**如何升级**: 打开命令行执行以下命令: `go get -u github.com/kataras/iris` 或者等待自动更新。 - -# Fr, 11 January 2019 | v11.1.1 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-11-january-2019--v1111) instead. - -# Su, 18 November 2018 | v11.1.0 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#su-18-november-2018--v1110) instead. - -# Fr, 09 November 2018 | v11.0.4 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-09-november-2018--v1104) instead. - -# Tu, 30 October 2018 | v11.0.2 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-30-october-2018--v1102) instead. - -# Su, 28 October 2018 | v11.0.1 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#su-28-october-2018--v1101) instead. - -# Su, 21 October 2018 | v11.0.0 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#su-21-october-2018--v1100) instead. - -# Sat, 11 August 2018 | v10.7.0 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#sat-11-august-2018--v1070) instead. - -# Tu, 05 June 2018 | v10.6.6 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-05-june-2018--v1066) instead. - -# Mo, 21 May 2018 | v10.6.5 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#mo-21-may-2018--v1065) instead. - -# We, 09 May 2018 | v10.6.4 - -- [fix issue 995](https://github.com/kataras/iris/commit/62457279f41a1f157869a19ef35fb5198694fddb) -- [fix issue 996](https://github.com/kataras/iris/commit/a11bb5619ab6b007dce15da9984a78d88cd38956) - -# We, 02 May 2018 | v10.6.3 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#we-02-may-2018--v1063) instead. - -# Tu, 01 May 2018 | v10.6.2 - -This history entry is not translated yet to the Chinese language yet, please refer to the english version of the [HISTORY entry](https://github.com/kataras/iris/blob/master/HISTORY.md#tu-01-may-2018--v1062) instead. - -# 2018 4月25日 | v10.6.1 版本更新 - -- 用最新版 BoltDB 重新实现 session (`sessiondb`) 存储:[/sessions/sessiondb/boltdb/database.go](sessions/sessiondb/boltdb/database.go), 相关示例 [/_examples/sessions/database/boltdb/main.go](_examples/sessions/database/boltdb/main.go). -- 修正 一个小问题 on [Badger sessiondb example](_examples/sessions/database/badger/main.go). `sessions.Config { Expires }` 字段由 `2 *time.Second` 调整为 `45 *time.Minute` . -- badger sessiondb 其他小改进. - -# 2018 4月22日 | v10.6.0 版本更新 - -- 修正 重定向问题 由 @wozz 提交: https://github.com/kataras/iris/pull/972. -- 修正 无法销毁子域名 session 问题 由 @Chengyumeng 提交: https://github.com/kataras/iris/pull/964. -- 添加 `OnDestroy(sid string)` 当 session 销毁时注册监听器 相关细节: https://github.com/kataras/iris/commit/d17d7fecbe4937476d00af7fda1c138c1ac6f34d. -- sessions 现在与注册数据库完全同步。 这涉及到很多内部改动,但 **这不影响你当前项目代码**. 我们只保留了 `badger` 和 `redis` 作为底部支持。 相关细节: https://github.com/kataras/iris/commit/f2c3a5f0cef62099fd4d77c5ccb14f654ddbfb5c - -# 2018 3月 24日 | v10.5.0 版本更新 - -### 新增 - -新增 缓存中间件客户端,更快的静态文件服务器. 详情 [点击](https://github.com/kataras/iris/pull/935). - -### 破坏式更新 - -改变 `ValueDefault(, error)` 为 `ValueDefault(key, defaultValue) ` 如同 `ctx.PostValueIntDefault` 或 `ctx.Values().GetIntDefault` 或 `sessions/session#GetIntDefault` 或 `context#URLParamIntDefault`. -由 @jefurry 提出 https://github.com/kataras/iris/issues/937. - -#### 如何升级现有代码 - -只需要移除第二个返回值即可. - -示例: [_examples/mvc/basic/main.go line 100](_examples/mvc/basic/main.go#L100)  `count,_ := c.Session.GetIntDefault("count", 1)` **变更为:** `count := c.Session.GetIntDefault("count", 1)`. - -> 请记住,如果您无法升级,那么就不要这样做,我们在此版本中没有任何安全修复程序,但在某些时候建议您最好进行升级,我们总是会添加您喜欢的新功能! - - -# 2018 3月14日 | v10.4.0 版本更新 - -- 修正 `APIBuilder, Party#StaticWeb` 和 `APIBuilder, Party#StaticEmbedded` 子分组内的前缀错误 -- 保留 `iris, core/router#StaticEmbeddedHandler` 并移除 `core/router/APIBuilder#StaticEmbeddedHandler`, (`Handler` 后缀) 这是全局性的,与 `Party` `APIBuilder` 无关。 -- 修正 路径 `{}` 中的路径清理 (我们已经在 [解释器](macro/interpreter) 级别转义了这些字符, 但是一些符号仍然被更高级别的API构建器删除) , 例如 `\\` 字符串的宏函数正则表达式内容 [927](https://github.com/kataras/iris/issues/927) by [commit e85b113476eeefffbc7823297cc63cd152ebddfd](https://github.com/kataras/iris/commit/e85b113476eeefffbc7823297cc63cd152ebddfd) -- 同步 `golang.org/x/sys/unix` - -## 重要变更 - -我们使用新工具将静态文件的速度提高了8倍, 这是 go-bindata 的一个分支,对我们来说,一些不必要的东西被移除了,并且包含一些提高性能的补充。 - -## Reqs/sec 使用 [shuLhan/go-bindata](https://github.com/shuLhan/go-bindata) 和 备选方案对比 - -![go-bindata](https://github.com/kataras/bindata/raw/master/go-bindata-benchmark.png) - -## Reqs/sec 使用 [kataras/bindata](https://github.com/kataras/bindata) - -![bindata](https://github.com/kataras/bindata/raw/master/bindata-benchmark.png) - -**新增** 方法 `Party#StaticEmbeddedGzip` 与 `Party#StaticEmbedded` 参数相同. 不同处在于 **新增** `StaticEmbeddedGzip` 从 `bindata` 接收 `GzipAsset` 和 `GzipAssetNames` (go get -u github.com/kataras/bindata/cmd/bindata). - -你可以在同个文件夹里同时使用 `bindata` 和 `go-bindata` 工具, 第一个用于嵌入静态文件 (javascript, css, ...) 第二个用于静态编译模板! - -完整示例: [_examples/file-server/embedding-gziped-files-into-app/main.go](_examples/file-server/embedding-gziped-files-into-app/main.go). - - -# 2018 3月10号 | v10.3.0 版本更新 - -- 只有一项 API 更改 [Application/Context/Router#RouteExists](https://godoc.org/github.com/kataras/iris/core/router#Router.RouteExists), 将 `Context` 作为第一参数,而不是最后一个。 - -- 修正 cors 中间件 https://github.com/iris-contrib/middleware/commit/048e2be034ed172c6754448b8a54a9c55debad46, 相关问题: https://github.com/kataras/iris/issues/922 (目前仍在等待验证). - -- 添加 `Context#NextOr` 和 `Context#NextOrNotFound` 方法 - -```go -// NextOr 检查程序链上是否有下一个处理程序,如果是,则执行它 -// 否则根据给定的处理程序设置分配给 Context 程序链,并且执行第一个控制器。 -// -// 如果下一个处理器存在并执行,则返回true,否则返回false -// -// 请注意,如果没有找到下一个处理程序并且处理程序缺失, -// 会发送 (404) 状态码到客户端,并停止执行。 -NextOr(handlers ...Handler) bool -// NextOrNotFound 检查程序链上是否存在下一个处理程序,如果有则执行 -// 其他情况会发送 404 状态码,并停止执行。 -// -// 如果下一个控制器存在并执行,返回 true , 其他情况 false. -NextOrNotFound() bool -``` - -- 新增方法 `Party#AllowMethods` 如果在 `Handle, Get, Post...` 之前调用,则会将路由克隆到该方法. - -- 修复 POST 请求尾部斜杠重定向问题: https://github.com/kataras/iris/issues/921 https://github.com/kataras/iris/commit/dc589d9135295b4d080a9a91e942aacbfe5d56c5 - -- 新增示例 通过 `iris#UnmarshalerFunc` 自定义解码, 新增 `context#ReadXML` 使用示例, [相关示例](https://github.com/kataras/iris/tree/master/_examples#how-to-read-from-contextrequest-httprequest)via https://github.com/kataras/iris/commit/78cd8e5f677fe3ff2c863c5bea7d1c161bf4c31e. - -- 新增自定义路由宏功能示例, 相关讨论 https://github.com/kataras/iris/issues/918, [示例代码](https://github.com/kataras/iris/blob/master/_examples/routing/dynamic-path/main.go#L144-L158), https://github.com/kataras/iris/commit/a7690c71927cbf3aa876592fab94f04cada91b72 - -- 为 `Pongo` 新增 `AsValue()` 和 `AsSaveValue()` @neenar https://github.com/kataras/iris/pull/913 - -- 删除 `context#UnmarshalBody` 上不必要的反射 https://github.com/kataras/iris/commit/4b9e41458b62035ea4933789c0a132c3ef2a90cc - -# 2018 2月15号 | v10.2.1 版本更新 - -修正 子域名 (subdomain) 的 `StaticEmbedded` 和 `StaticWeb` 不存在错误, 由 [@speedwheel](https://github.com/speedwheel) 通过 [facebook page's chat](https://facebook.com/iris.framework) 反馈。 - -# 2018 2月8号 | v10.2.0 版本更新 - -新的小版本, 因为它包含一个 **破坏性变动** 和一个新功能 `Party#Reset` - -### Party#Done 特性变动 和 新增 Party#DoneGlobal 介绍 - -正如 @likakuli 指出的那样 https://github.com/kataras/iris/issues/901, 以前 `Done` 注册的处理器,在全局范围内会替代子处理器,因为在引入 `UseGlobal` 这概念之前,缺少稳定性. 现在是时候了, 新的 `Done` 应该在相关的路由之前调用, **新增** `DoneGlobal` 之前的`Done` 使用相同; 顺序无关紧要,他只是结束处理附加到当前的注册程序, 全局性的 (所有子域名,分组). - -[routing/writing-a-middleware](_examples/routing/writing-a-middleware) 路由中间件示例更新, 列举了使用方式变化, 如果之前使用过 Iris ,并熟悉内置函数方法名称,请区分 `DoneGlobal` 和 `Done` 的不同. - -### Party#Reset - -新增 `Party#Reset()` 函数,以便重置上级分组通过 `Use` 和 `Done` 注册的处理方法, 没有什么特别之处,它只是清除当前分组实例的 `middleware` 和 `doneHandlers`,详情参见 `core/router#APIBuilder`. - -### 更新方法 - -只需要将现有的 `.Done` 替换为 `.DoneGlobal` 就可以了。 - -# 2018 2月6号 | v10.1.0 版本更新 - -新特性: - -- 多级域名跳转, 相关示例 [here](https://github.com/kataras/iris/blob/master/_examples/subdomains/redirect/main.go) -- 缓存中间件携带 `304` 状态码, 缓存期间的请求,服务器只响应状态, 相关示例 [here](https://github.com/kataras/iris/blob/master/_examples/cache/client-side/main.go) -- `websocket/Connection#IsJoined(roomName string)` 新增方法,检查用户是否加入房间。 未加入的连接不能发送消息,此检查是可选的. - -详情: - -- 更新上游 vendor/golang/crypto 包到最新版本, 我们总是跟进依赖关系的任何修复和有意义的更新. -- [改进:不在gzip响应的WriteString和Writef上强制设置内容类型(如果已经存在的话)](https://github.com/kataras/iris/commit/af79aad11932f1a4fcbf7ebe28274b96675d0000) -- [新增:websocket/Connection#IsJoined](https://github.com/kataras/iris/commit/cb9e30948c8f1dd099f5168218d110765989992e) -- [修复:#897](https://github.com/kataras/iris/commit/21cb572b638e82711910745cfae3c52d836f01f9) -- [新增:context#StatusCodeNotSuccessful 变量用来定制 rfc2616-sec10](https://github.com/kataras/iris/commit/c56b7a3f04d953a264dfff15dadd2b4407d62a6f) -- [修复:示例 routing/dynamic-path/main.go#L101](https://github.com/kataras/iris/commit/0fbf1d45f7893cb1393759b7362444f3d381d182) -- [新增:缓存中间件 `iris.Cache304`](https://github.com/kataras/iris/commit/1722355870174cecbc12f7beff8514b058b3b912) -- [修复:示例 csrf](https://github.com/kataras/iris/commit/a39e3d7d6cf528e51e6c7e32a884a8d9f2fadc0b) -- [取消:Configuration.RemoteAddrHeaders 默认值](https://github.com/kataras/iris/commit/47108dc5a147a8b23de61bef86fe9327f0781396) -- [新增:vscode 扩展链接和徽章](https://github.com/kataras/iris/commit/6f594c0a7c641cc98bd683163fffbf5fa5fc8de6) -- [新增:`app.View` 示例 用于解析和编写HTTP之外的模板(类似于上下文#视图)](_examples/view/write-to) -- [新增:支持多级域名跳转](https://github.com/kataras/iris/commit/12d7df113e611a75088c2a72774dab749d2c7685). - -# 2018 1月16号 | v10.0.2 版本更新 - -## 安全更新 | `iris.AutoTLS` - -**建议升级**, 包含几天前修复了 letsencrypt.org 禁用 tls-sni 的问题,这导致几乎每个启用了 https 的 golang 服务器都无法正常工作,因此支持添加了 http-01 类型。 现在服务器会尝试所有可用的 letsencrypt 类型。 - -更多相关资讯: - -- https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241 -- https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac - -# 2018 1月15号 | v10.0.1 版本更新 - -该版本暂未发现重大问题,但如果你使用 [cache](cache) 包的话,这里有些更新或许正好解决某些问题。 - -- 修复缓存在同一控制器多个方法中,返回相同内容问题 https://github.com/kataras/iris/pull/852, 问题报告:https://github.com/kataras/iris/issues/850 -- 问题修正 https://github.com/kataras/iris/pull/862 -- 当 `view#Engine##Reload` 为 true,`ExecuteWriter -> Load` 不能同时使用问题,相关问题 :https://github.com/kataras/iris/issues/872 -- 由Iris提供支持的开源项目的徽章, 学习如何将徽章添加到您的开源项目中 [FAQ.md](FAQ.md) -- 上游更新 `golang/crypto` 修正 [tls-sni challenge disabled](https://letsencrypt.status.io/pages/incident/55957a99e800baa4470002da/5a55777ed9a9c1024c00b241) https://github.com/golang/crypto/commit/13931e22f9e72ea58bb73048bc752b48c6d4d4ac (**关系到 iris.AutoTLS**) - -## 新增捐助 - -1. https://opencollective.com/cetin-basoz - -## 新增翻译 - -1. 中文版 README_ZH.md and HISTORY_ZH.md 由 @Zeno-Code 翻译 https://github.com/kataras/iris/pull/858 -2. 俄语版 README_RU.md 由 @merrydii 翻译 https://github.com/kataras/iris/pull/857 -3. 希腊版 README_GR.md and HISTORY_GR.md https://github.com/kataras/iris/commit/8c4e17c2a5433c36c148a51a945c4dc35fbe502a#diff-74b06c740d860f847e7b577ad58ddde0 and https://github.com/kataras/iris/commit/bb5a81c540b34eaf5c6c8e993f644a0e66a78fb8 - -## 新增示例 - -1. [MVC - Register Middleware](_examples/mvc/middleware) - -## 新增文章 - -1. [A Todo MVC Application using Iris and Vue.js](https://hackernoon.com/a-todo-mvc-application-using-iris-and-vue-js-5019ff870064) -2. [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](bit.ly/2lmKaAZ) - -# 2018 元旦 | v10.0.0 版本发布 - -我们必须感谢 [Mrs. Diana](https://www.instagram.com/merry.dii/) 帮我们绘制的漂亮 [logo](https://iris-go.com/images/icon.svg)! - -如果有设计相关的需求,你可以[发邮件](mailto:Kovalenkodiana8@gmail.com)给他,或者通过 [instagram](https://www.instagram.com/merry.dii/) 给他发信息。 - -

- -

- -在这个版本中,有许多内部优化改进,但只有两个重大变更和新增一个叫做 **hero** 的特性。 - -> 新版本有 75 + 的变更提交, 如果你需要升级 Iris 请仔细阅读本文档。 为什么版本 9 跳过了? 你猜... - -## Hero 特性 - -新增包 [hero](hero) 可以绑定处理任何依赖 `handlers` 的对象或函数。Hero funcs 可以返回任何类型的值,并发送给客户端。 - -> 之前的绑定没有编辑器的支持, 新包 `hero` 为 Iris 带来真正的安全绑定。 Iris 会在服务器运行之前计算所有内容,所以它执行速度高,接近于原生性能。 - -下面你会看到我们为你准备的一些截图,以便于理解: - -### 1. 路径参数 - 构建依赖 - -![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png) - -### 2. 服务 - 静态依赖 - -![](https://github.com/kataras/explore/raw/master/iris/hero/hero-2-monokai.png) - -### 3. 请求之前 - 动态依赖 - -![](https://github.com/kataras/explore/raw/master/iris/hero/hero-3-monokai.png) - -`hero funcs` 非常容易理解,当你用过之后 **在也回不去了**. - -示例: - -- [基本用法](_examples/hero/basic/main.go) -- [使用概览](_examples/hero/overview) - -## MVC - -如果要使用 `mvc` ,必须先理解 `hero` 包,因为`mvc`在内部使用`hero`作为路由控制器的方法,同样的规则也适用于你的控制器的方法。 - -With this version you can register **any controller's methods as routes manually**, you can **get a route based on a method name and change its `Name` (useful for reverse routing inside templates)**, you can use any **dependencies** registered from `hero.Register` or `mvc.New(iris.Party).Register` per mvc application or per-controller, **you can still use `BeginRequest` and `EndRequest`**, you can catch **`BeforeActivation(b mvc.BeforeActivation)` to add dependencies per controller and `AfterActivation(a mvc.AfterActivation)` to make any post-validations**, **singleton controllers when no dynamic dependencies are used**, **Websocket controller, as simple as a `websocket.Connection` dependency** and more... - -示例: - -**如果你之前使用过 MVC ,请仔细阅读:MVC 包含一些破坏性的改进,但新的方式可以做更多,会让程序执行更快** - -**请阅读我们为你准备的示例** - -如果你现在需要升级,请对比新旧版本示例的不同,便于理解。 - -| NEW | OLD | -| -----------|-------------| -| [Hello world](_examples/mvc/hello-world/main.go) | [OLD Hello world](https://github.com/kataras/iris/blob/v8/_examples/mvc/hello-world/main.go) | -| [Session Controller](_examples/mvc/session-controller/main.go) | [OLD Session Controller](https://github.com/kataras/iris/blob/v8/_examples/mvc/session-controller/main.go) | -| [Overview - Plus Repository and Service layers](_examples/mvc/overview) | [OLD Overview - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/overview) | -| [Login showcase - Plus Repository and Service layers](_examples/mvc/login) | [OLD Login showcase - Plus Repository and Service layers](https://github.com/kataras/iris/tree/v8/_examples/mvc/login) | -| [Singleton](_examples/mvc/singleton) | **新增** | -| [Websocket Controller](_examples/mvc/websocket) | **新增** | -| [Vue.js Todo MVC](_examples/tutorial/vuejs-todo-mvc) | **新增** | - -## context#PostMaxMemory - -移除旧版本的常量 `context.DefaultMaxMemory` 替换为配置 `WithPostMaxMemory` 方法. - -```go -// WithPostMaxMemory 设置客户端向服务器 post 提交数据的最大值 -// 他不同于 request body 的值大小,如果有相关需求请使用 -// `context#SetMaxRequestBodySize` 或者 `iris#LimitRequestBodySize` -// -// 默认值为 32MB 或者 32 << 20 -func WithPostMaxMemory(limit int64) Configurator -``` - -如果你使用老版本的常量,你需要更改一行代码. - -使用方式: - -```go -import "github.com/kataras/iris" - -func main() { - app := iris.New() - // [...] - - app.Run(iris.Addr(":8080"), iris.WithPostMaxMemory(10 << 20)) -} -``` - -## context#UploadFormFiles - -新方法可以多文件上传, 应用于常见的上传操作, 它是一个非常有用的函数。 - -```go -// UploadFormFiles 将所有接收到的文件从客户端上传到系统物理位置 destDirectory。 -// -// The second optional argument "before" gives caller the chance to -// modify the *miltipart.FileHeader before saving to the disk, -// it can be used to change a file's name based on the current request, -// all FileHeader's options can be changed. You can ignore it if -// you don't need to use this capability before saving a file to the disk. -// -// Note that it doesn't check if request body streamed. -// -// Returns the copied length as int64 and -// a not nil error if at least one new file -// can't be created due to the operating system's permissions or -// http.ErrMissingFile if no file received. -// -// If you want to receive & accept files and manage them manually you can use the `context#FormFile` -// instead and create a copy function that suits your needs, the below is for generic usage. -// -// The default form's memory maximum size is 32MB, it can be changed by the -// `iris#WithPostMaxMemory` configurator at main configuration passed on `app.Run`'s second argument. -// -// See `FormFile` to a more controlled to receive a file. -func (ctx *context) UploadFormFiles( - destDirectory string, - before ...func(string, string), - ) (int64, error) -``` - -这里是相关示例 [here](_examples/http_request/upload-files/main.go). - -## context#View - -这里有个小更新,增加可选的第二个参数,用来绑定模版变量。提示:这种绑定方式,会忽略其他变量的绑定。 -如果要忽略其他模版变量,之前是在 `ViewData` 上绑定一个空字符串,现在可以直接通过 View 方法添加。 - -```go -func(ctx iris.Context) { - ctx.ViewData("", myItem{Name: "iris" }) - ctx.View("item.html") -} -``` - -等同于: - -```go -func(ctx iris.Context) { - ctx.View("item.html", myItem{Name: "iris" }) -} -``` - -```html -html 模版中调用: {{.Name}} -``` - -## context#YAML - -新增 `context#YAML` 函数, 解析结构体到 yaml。 - -```go -//使用 yaml 包的 Marshal 的方法解析,并发送到客户端。 -func YAML(v interface{}) (int, error) -``` - -## Session#GetString - -`sessions/session#GetString` 可以获取 session 的变量值(可以是 integer 类型),就像内存缓存、Context 上下文储存的值。 +# Mo, 22 July 2019 | v11.2.0 diff --git a/README.md b/README.md index b5ae7669..4c5256ad 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # Iris Web Framework - -[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=flat-square)](https://travis-ci.org/kataras/iris) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkataras%2Firis.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkataras%2Firis?ref=badge_shield) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris) [![chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://chat.iris-go.com) [![view examples](https://img.shields.io/badge/routing%20by-example-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/tree/master/_examples/routing) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=flat-square)](https://github.com/kataras/iris/releases) + + +[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases) Iris is a fast, simple yet fully featured and very efficient web framework for Go. Routing is powered by the [muxie](https://github.com/kataras/muxie#philosophy) project. @@ -12,56 +13,6 @@ Iris offers a complete and decent solution and support for all gophers around th Learn what [others say about Iris](#support) and [star](https://github.com/kataras/iris/stargazers) this github repository to stay [up to date](https://facebook.com/iris.framework). -## Ghost? No More! Support as first class citizen - -Have you bored of waiting weeks or months for someone to respond to your github issue? Yes, **me too**. If you choose Iris for your main backend development you will never be like a ghost again. - -Iris is one of the few public github repositories that offers real support to individuals and collectivities, including companies. Unbeatable **free support**[*](#support) for three years and still counting. Navigate to the issues to see by yourself. - -In these difficult and restless days **we stand beside you**. We **do not judge bad english writing**, no matter who you are, we will be here for you. - -Check below the features and the hard work that we putted to improve how the internet is built. If you really like it and appreciate it, give a star to this github **repository for the public.** - -## Benchmarks - -### Iris vs .NET Core vs Expressjs - -[![Iris vs .NET Core(C#) vs Node.js (Express)](_benchmarks/benchmarks_graph_22_october_2018_gray.png)](_benchmarks/README.md) - -_Updated at: [Monday, 22 October 2018](_benchmarks/README.md)_ - -### Third-party - -[![](_benchmarks/benchmarks_third_party_source_snapshot_go_23_october_2018.png)](https://github.com/iris-contrib/third-party-benchmarks#full-table) - -> Last updated at: 01 March of 2019. Click to the image to view all results. You can run this in your own hardware by following the [steps here](https://github.com/iris-contrib/third-party-benchmarks#usage). - -## Philosophy - -The Iris philosophy is to provide robust tooling for HTTP, making it a great solution for single page applications, web sites, hybrids, or public HTTP APIs. Keep note that, so far, iris is the fastest web framework ever created in terms of performance. - -Iris does not force you to use any specific ORM or template engine. With support for the most used template engines, you can quickly craft the perfect application. - -## Installation - -The only requirement is the [Go Programming Language](https://golang.org/dl/), version 1.12 and above. - -```sh -$ go get github.com/kataras/iris@v11.2.0 -``` - -Or inside your `go.mod` file: - -```sh -module your_project_name - -go 1.12 - -require ( - github.com/kataras/iris v11.2.0 -) -``` - ## Quick start ```sh @@ -91,966 +42,6 @@ func main() { $ go run example.go ``` -## API Examples - -### Using Get, Post, Put, Patch, Delete and Options - -```go -func main() { - // Creates an application with default middleware: - // logger and recovery (crash-free) middleware. - app := iris.Default() - - app.Get("/someGet", getting) - app.Post("/somePost", posting) - app.Put("/somePut", putting) - app.Delete("/someDelete", deleting) - app.Patch("/somePatch", patching) - app.Head("/someHead", head) - app.Options("/someOptions", options) - - app.Run(iris.Addr(":8080")) -} -``` - -### Parameters in path - -| Param Type | Go Type | Validation | Retrieve Helper | -| -----------------|------|-------------|------| -| `:string` | string | anything (single path segment) | `Params().Get` | -| `:int` | int | -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch | `Params().GetInt` | -| `:int8` | int8 | -128 to 127 | `Params().GetInt8` | -| `:int16` | int16 | -32768 to 32767 | `Params().GetInt16` | -| `:int32` | int32 | -2147483648 to 2147483647 | `Params().GetInt32` | -| `:int64` | int64 | -9223372036854775808 to 9223372036854775807 | `Params().GetInt64` | -| `:uint` | uint | 0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32), depends on the host arch | `Params().GetUint` | -| `:uint8` | uint8 | 0 to 255 | `Params().GetUint8` | -| `:uint16` | uint16 | 0 to 65535 | `Params().GetUint16` | -| `:uint32` | uint32 | 0 to 4294967295 | `Params().GetUint32` | -| `:uint64` | uint64 | 0 to 18446744073709551615 | `Params().GetUint64` | -| `:bool` | bool | "1" or "t" or "T" or "TRUE" or "true" or "True" or "0" or "f" or "F" or "FALSE" or "false" or "False" | `Params().GetBool` | -| `:alphabetical` | string | lowercase or uppercase letters | `Params().Get` | -| `:file` | string | lowercase or uppercase letters, numbers, underscore (_), dash (-), point (.) and no spaces or other special characters that are not valid for filenames | `Params().Get` | -| `:path` | string | anything, can be separated by slashes (path segments) but should be the last part of the route path | `Params().Get` | - -**Usage**: - -```go -app.Get("/users/{id:uint64}", func(ctx iris.Context){ - id := ctx.Params().GetUint64Default("id", 0) - // [...] -}) -``` - -| Built-in Func | Param Types | -| -----------|---------------| -| `regexp`(expr string) | :string | -| `prefix`(prefix string) | :string | -| `suffix`(suffix string) | :string | -| `contains`(s string) | :string | -| `min`(minValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :string(char length), :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 | -| `max`(maxValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :string(char length), :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 | -| `range`(minValue, maxValue int or int8 or int16 or int32 or int64 or uint8 or uint16 or uint32 or uint64 or float32 or float64) | :int, :int8, :int16, :int32, :int64, :uint, :uint8, :uint16, :uint32, :uint64 | - -**Usage**: - -```go -app.Get("/profile/{name:alphabetical max(255)}", func(ctx iris.Context){ - name := ctx.Params().Get("name") - // len(name) <=255 otherwise this route will fire 404 Not Found - // and this handler will not be executed at all. -}) -``` - -**Do It Yourself**: - -The `RegisterFunc` can accept any function that returns a `func(paramValue string) bool`. -Or just a `func(string) bool`. -If the validation fails then it will fire `404` or whatever status code the `else` keyword has. - -```go -latLonExpr := "^-?[0-9]{1,3}(?:\\.[0-9]{1,10})?$" -latLonRegex, _ := regexp.Compile(latLonExpr) - -// Register your custom argument-less macro function to the :string param type. -// MatchString is a type of func(string) bool, so we use it as it is. -app.Macros().Get("string").RegisterFunc("coordinate", latLonRegex.MatchString) - -app.Get("/coordinates/{lat:string coordinate()}/{lon:string coordinate()}", func(ctx iris.Context) { - ctx.Writef("Lat: %s | Lon: %s", ctx.Params().Get("lat"), ctx.Params().Get("lon")) -}) -``` - -Register your custom macro function which accepts two int arguments. - -```go - -app.Macros().Get("string").RegisterFunc("range", func(minLength, maxLength int) func(string) bool { - return func(paramValue string) bool { - return len(paramValue) >= minLength && len(paramValue) <= maxLength - } -}) - -app.Get("/limitchar/{name:string range(1,200) else 400}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - ctx.Writef(`Hello %s | the name should be between 1 and 200 characters length - otherwise this handler will not be executed`, name) -}) -``` - -Register your custom macro function which accepts a slice of strings `[...,...]`. - -```go -app.Macros().Get("string").RegisterFunc("has", func(validNames []string) func(string) bool { - return func(paramValue string) bool { - for _, validName := range validNames { - if validName == paramValue { - return true - } - } - - return false - } -}) - -app.Get("/static_validation/{name:string has([kataras,gerasimos,maropoulos])}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - ctx.Writef(`Hello %s | the name should be "kataras" or "gerasimos" or "maropoulos" - otherwise this handler will not be executed`, name) -}) -``` - -**Example Code**: - -```go -func main() { - app := iris.Default() - - // This handler will match /user/john but will not match neither /user/ or /user. - app.Get("/user/{name}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - ctx.Writef("Hello %s", name) - }) - - // This handler will match /users/42 - // but will not match /users/-1 because uint should be bigger than zero - // neither /users or /users/. - app.Get("/users/{id:uint64}", func(ctx iris.Context) { - id := ctx.Params().GetUint64Default("id", 0) - ctx.Writef("User with ID: %d", id) - }) - - // However, this one will match /user/john/send and also /user/john/everything/else/here - // but will not match /user/john neither /user/john/. - app.Post("/user/{name:string}/{action:path}", func(ctx iris.Context) { - name := ctx.Params().Get("name") - action := ctx.Params().Get("action") - message := name + " is " + action - ctx.WriteString(message) - }) - - app.Run(iris.Addr(":8080")) -} -``` - -> If parameter type is missing then defaults to `string`, therefore `{name:string}` and `{name}` do the same exactly thing. - -> Learn more about path parameter's types by navigating [here](_examples/routing/dynamic-path/main.go#L31). - - -### Dependency Injection - -The package [hero](hero) contains features for binding any object or functions that `handlers` can use, these are called dependencies. - -With Iris you get truly safe bindings thanks to the [hero](_examples/hero) [package](hero). It is blazing-fast, near to raw handlers performance because Iris calculates everything before the server even goes online! - -Below you will see some screenshots I prepared to facilitate understanding: - -#### 1. Path Parameters - Built-in 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) - -`hero funcs` are very easy to understand and when you start using them **you never go back**. - -> With Iris you also get real and [blazing-fast](_benchmarks) [MVC support](_examples/mvc) which uses "hero" under the hoods. - -### Querystring parameters - -```go -func main() { - app := iris.Default() - - // Query string parameters are parsed using the existing underlying request object. - // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe. - app.Get("/welcome", func(ctx iris.Context) { - firstname := ctx.URLParamDefault("firstname", "Guest") - // shortcut for ctx.Request().URL.Query().Get("lastname"). - lastname := ctx.URLParam("lastname") - - ctx.Writef("Hello %s %s", firstname, lastname) - }) - - app.Run(iris.Addr(":8080")) -} -``` - -### Multipart/Urlencoded Form - -```go -func main() { - app := iris.Default() - - app.Post("/form_post", func(ctx iris.Context) { - message := ctx.FormValue("message") - nick := ctx.FormValueDefault("nick", "anonymous") - - ctx.JSON(iris.Map{ - "status": "posted", - "message": message, - "nick": nick, - }) - }) - - app.Run(iris.Addr(":8080")) -} -``` - -### Another example: query + post form - -``` -POST /post?id=1234&page=1 HTTP/1.1 -Content-Type: application/x-www-form-urlencoded - -name=manu&message=this_is_great -``` - -```go -func main() { - app := iris.Default() - - app.Post("/post", func(ctx iris.Context) { - id := ctx.URLParam("id") - page := ctx.URLParamDefault("page", "0") - name := ctx.FormValue("name") - message := ctx.FormValue("message") - // or `ctx.PostValue` for POST, PUT & PATCH-only HTTP Methods. - - app.Logger().Infof("id: %s; page: %s; name: %s; message: %s", id, page, name, message) - }) - - app.Run(iris.Addr(":8080")) -} -``` - -``` -id: 1234; page: 1; name: manu; message: this_is_great -``` - -### Extract Referer - -```go -package main - -import ( - "github.com/kataras/iris" - "github.com/kataras/iris/context" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx context.Context) /* or iris.Context, it's the same for Go 1.9+. */ { - - // request header "referer" or url parameter "referer". - r := ctx.GetReferrer() - switch r.Type { - case context.ReferrerSearch: - ctx.Writef("Search %s: %s\n", r.Label, r.Query) - ctx.Writef("Google: %s\n", r.GoogleType) - case context.ReferrerSocial: - ctx.Writef("Social %s\n", r.Label) - case context.ReferrerIndirect: - ctx.Writef("Indirect: %s\n", r.URL) - } - }) - - app.Run(iris.Addr(":8080")) -} -``` - -How to `curl`: - -```bash -curl http://localhost:8080?referer=https://twitter.com/Xinterio/status/1023566830974251008 -curl http://localhost:8080?referer=https://www.google.com/search?q=Top+6+golang+web+frameworks&oq=Top+6+golang+web+frameworks -``` - -### Upload files - -- [single file upload](_examples/http_request/upload-file/main.go) -- [multi file upload](_examples/http_request/upload-files) - -```go -const maxSize = 5 << 20 // 5MB - -func main() { - app := iris.Default() - app.Post("/upload", iris.LimitRequestBodySize(maxSize), func(ctx iris.Context) { - // - // UploadFormFiles - // uploads any number of incoming files ("multiple" property on the form input). - // - - // The second, optional, argument - // can be used to change a file's name based on the request, - // at this example we will showcase how to use it - // by prefixing the uploaded file with the current user's ip. - ctx.UploadFormFiles("./uploads", beforeSave) - }) - - app.Run(iris.Addr(":8080")) -} - -func beforeSave(ctx iris.Context, file *multipart.FileHeader) { - ip := ctx.RemoteAddr() - // make sure you format the ip in a way - // that can be used for a file name (simple case): - ip = strings.Replace(ip, ".", "_", -1) - ip = strings.Replace(ip, ":", "_", -1) - - // you can use the time.Now, to prefix or suffix the files - // based on the current time as well, as an exercise. - // i.e unixTime := time.Now().Unix() - // prefix the Filename with the $IP- - // no need for more actions, internal uploader will use this - // name to save the file into the "./uploads" folder. - file.Filename = ip + "-" + file.Filename -} -``` - -How to `curl`: - -```bash -curl -X POST http://localhost:8080/upload \ - -F "files[]=@./myfile.zip" \ - -F "files[]=@./mysecondfile.zip" \ - -H "Content-Type: multipart/form-data" -``` - -### Grouping routes - -```go -func main() { - app := iris.Default() - - // Simple group: v1. - v1 := app.Party("/v1") - { - v1.Post("/login", loginEndpoint) - v1.Post("/submit", submitEndpoint) - v1.Post("/read", readEndpoint) - } - - // Simple group: v2. - v2 := app.Party("/v2") - { - v2.Post("/login", loginEndpoint) - v2.Post("/submit", submitEndpoint) - v2.Post("/read", readEndpoint) - } - - app.Run(iris.Addr(":8080")) -} -``` - -### Blank Iris without middleware by default - -Use - -```go -app := iris.New() -``` - -instead of - -```go -// Default with the Logger and Recovery middleware already attached. -app := iris.Default() -``` - -### Using middleware - -```go -import ( - "github.com/kataras/iris" - - "github.com/kataras/iris/middleware/recover" - "github.com/kataras/iris/middleware/logger" -) - -func main() { - // Creates an application without any middleware by default. - app := iris.New() - - // Recover middleware recovers from any panics and writes a 500 if there was one. - app.Use(recover.New()) - - requestLogger := logger.New(logger.Config{ - // Status displays status code - Status: true, - // IP displays request's remote address - IP: true, - // Method displays the http method - Method: true, - // Path displays the request path - Path: true, - // Query appends the url query to the Path. - Query: true, - - // if !empty then its contents derives from `ctx.Values().Get("logger_message") - // will be added to the logs. - MessageContextKeys: []string{"logger_message"}, - - // if !empty then its contents derives from `ctx.GetHeader("User-Agent") - MessageHeaderKeys: []string{"User-Agent"}, - }) - app.Use(requestLogger) - - // Per route middleware, you can add as many as you desire. - app.Get("/benchmark", MyBenchLogger(), benchEndpoint) - - // Authorization party /user. - // authorized := app.Party("/user", AuthRequired()) - // exactly the same as: - authorized := app.Party("/user") - // per party middleware! in this case we use the custom created - // AuthRequired() middleware just in the "authorized" group/party. - authorized.Use(AuthRequired()) - { - authorized.Post("/login", loginEndpoint) - authorized.Post("/submit", submitEndpoint) - authorized.Post("/read", readEndpoint) - - // nested group: /user/testing - testing := authorized.Party("/testing") - testing.Get("/analytics", analyticsEndpoint) - } - - // Listen and serve on http://0.0.0.0:8080 - app.Run(iris.Addr(":8080")) -} -``` - -### How to write log file - -```go -package main - -import ( - "os" - "time" - - "github.com/kataras/iris" -) - -// Get a filename based on the date, just for the sugar. -func todayFilename() string { - today := time.Now().Format("Jan 02 2006") - return today + ".txt" -} - -func newLogFile() *os.File { - filename := todayFilename() - // Open the file, this will append to the today's file if server restarted. - f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) - if err != nil { - panic(err) - } - - return f -} - -func main() { - f := newLogFile() - defer f.Close() - - app := iris.New() - // Attach the file as logger, remember, iris' app logger is just an io.Writer. - // Use the following code if you need to write the logs to file and console at the same time. - // app.Logger().SetOutput(io.MultiWriter(f, os.Stdout)) - app.Logger().SetOutput(f) - - app.Get("/ping", func(ctx iris.Context) { - // for the sake of simplicity, in order see the logs at the ./_today_.txt - ctx.Application().Logger().Infof("Request path: %s", ctx.Path()) - ctx.WriteString("pong") - }) - - // Navigate to http://localhost:8080/ping - // and open the ./logs{TODAY}.txt file. - app.Run( - iris.Addr(":8080"), - iris.WithoutBanner, - iris.WithoutServerError(iris.ErrServerClosed), - ) -} -``` - -### Model binding and validation - -Iris uses [**go-playground/validator.v9**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v9#hdr-Baked_In_Validators_and_Tags). - -Example [detail code](_examples/http_request/read-json-struct-validation/main.go). - -Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`. - -```go -package main - -import ( - "fmt" - - "github.com/kataras/iris" - "gopkg.in/go-playground/validator.v9" -) - -// User contains user information. -type User struct { - FirstName string `json:"fname"` - LastName string `json:"lname"` - Age uint8 `json:"age" validate:"gte=0,lte=130"` - Email string `json:"email" validate:"required,email"` - FavouriteColor string `json:"favColor" validate:"hexcolor|rgb|rgba"` - Addresses []*Address `json:"addresses" validate:"required,dive,required"` -} - -// Address houses a users address information. -type Address struct { - Street string `json:"street" validate:"required"` - City string `json:"city" validate:"required"` - Planet string `json:"planet" validate:"required"` - Phone string `json:"phone" validate:"required"` -} - -// Use a single instance of Validate, it caches struct info. -var validate *validator.Validate - -func main() { - validate = validator.New() - - // Register validation for 'User' - // NOTE: only have to register a non-pointer type for 'User', validator - // internally dereferences during it's type checks. - validate.RegisterStructValidation(UserStructLevelValidation, User{}) - - app := iris.New() - app.Post("/user", func(ctx iris.Context) { - var user User - if err := ctx.ReadJSON(&user); err != nil { - // Handle error. - } - - // Returns InvalidValidationError for bad validation input, - // nil or ValidationErrors ( []FieldError ) - err := validate.Struct(user) - if err != nil { - - // This check is only needed when your code could produce - // an invalid value for validation such as interface with nil - // value most including myself do not usually have code like this. - if _, ok := err.(*validator.InvalidValidationError); ok { - ctx.StatusCode(iris.StatusInternalServerError) - ctx.WriteString(err.Error()) - return - } - - ctx.StatusCode(iris.StatusBadRequest) - for _, err := range err.(validator.ValidationErrors) { - fmt.Println() - fmt.Println(err.Namespace()) - fmt.Println(err.Field()) - fmt.Println(err.StructNamespace()) - fmt.Println(err.StructField()) - fmt.Println(err.Tag()) - fmt.Println(err.ActualTag()) - fmt.Println(err.Kind()) - fmt.Println(err.Type()) - fmt.Println(err.Value()) - fmt.Println(err.Param()) - fmt.Println() - } - - return - } - - // save user to database. - }) - - app.Run(iris.Addr(":8080")) -} - -func UserStructLevelValidation(sl validator.StructLevel) { - user := sl.Current().Interface().(User) - - if len(user.FirstName) == 0 && len(user.LastName) == 0 { - sl.ReportError(user.FirstName, "FirstName", "fname", "fnameorlname", "") - sl.ReportError(user.LastName, "LastName", "lname", "fnameorlname", "") - } -} -``` - -```json -{ - "fname": "", - "lname": "", - "age": 45, - "email": "mail@example.com", - "favColor": "#000", - "addresses": [{ - "street": "Eavesdown Docks", - "planet": "Persphone", - "phone": "none", - "city": "Unknown" - }] -} -``` - -### Websockets - -```go -package main - -import ( - "fmt" - - "github.com/kataras/iris" - "github.com/kataras/iris/websocket" -) - -func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.ServeFile("websockets.html", false) // second parameter: enable gzip? - }) - - setupWebsocket(app) - - // x2 - // http://localhost:8080 - // http://localhost:8080 - // write something, press submit, see the result. - app.Run(iris.Addr(":8080")) -} - -func setupWebsocket(app *iris.Application) { - // create our echo websocket server - ws := websocket.New(websocket.Config{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, - }) - ws.OnConnection(handleConnection) - - // register the server on an endpoint. - // see the inline javascript code in the websockets.html, - // this endpoint is used to connect to the server. - app.Get("/echo", ws.Handler()) - // serve the javascript built-in client-side library, - // see websockets.html script tags, this path is used. - app.Any("/iris-ws.js", websocket.ClientHandler()) -} - -func handleConnection(c websocket.Connection) { - // Read events from browser - c.On("chat", func(msg string) { - // Print the message to the console, c.Context() is the iris's http context. - fmt.Printf("%s sent: %s\n", c.Context().RemoteAddr(), msg) - // Write message back to the client message owner with: - // c.Emit("chat", msg) - // Write message to all except this client with: - c.To(websocket.Broadcast).Emit("chat", msg) - }) -} -``` - -**websockets.html** - -```html - - - - - - - -

-
-
-
-
-```
-
-Navigate to the [_examples/websocket](_examples/websocket) folder for more.
-
-### Cookies
-
-> Are you looking about [http sessions instead?](_examples/sessions)
-
-Let's write a simple application which will make use of the HTTP Cookies.
-
-```sh
-$ cat _examples/cookies/basic/main.go
-```
-
-```go
-package main
-
-import "github.com/kataras/iris"
-
-func newApp() *iris.Application {
-    app := iris.New()
-
-    // Set A Cookie.
-    app.Get("/cookies/{name}/{value}", func(ctx iris.Context) {
-        name := ctx.Params().Get("name")
-        value := ctx.Params().Get("value")
-
-        ctx.SetCookieKV(name, value)
-
-        ctx.Writef("cookie added: %s = %s", name, value)
-    })
-
-    // Retrieve A Cookie.
-    app.Get("/cookies/{name}", func(ctx iris.Context) {
-        name := ctx.Params().Get("name")
-
-        value := ctx.GetCookie(name)
-
-        ctx.WriteString(value)
-    })
-
-    // Delete A Cookie.
-    app.Delete("/cookies/{name}", func(ctx iris.Context) {
-        name := ctx.Params().Get("name")
-
-        ctx.RemoveCookie(name)
-
-        ctx.Writef("cookie %s removed", name)
-    })
-
-    return app
-}
-
-func main() {
-    app := newApp()
-
-    // GET:    http://localhost:8080/cookies/my_name/my_value
-    // GET:    http://localhost:8080/cookies/my_name
-    // DELETE: http://localhost:8080/cookies/my_name
-    app.Run(iris.Addr(":8080"))
-}
-```
-
-* Alternatively, use a regular `http.Cookie`: `ctx.SetCookie(&http.Cookie{...})`
-* If you want to set custom the path: `ctx.SetCookieKV(name, value, iris.CookiePath("/custom/path/cookie/will/be/stored"))`.
-* If you want to be available only to the current request path: `ctx.SetCookieKV(name, value, iris.CookieCleanPath /* or iris.CookiePath("") */)`
-    * `iris.CookieExpires(time.Duration)`
-    * `iris.CookieHTTPOnly(false)`
-* `ctx.Request().Cookie(name)` is also available, it's the `net/http` approach
-* Learn more about path parameter's types by clicking [here](_examples/routing/dynamic-path/main.go#L31).
-
-### Testing
-
-Iris offers an incredible support for the [httpexpect](https://github.com/gavv/httpexpect), a Testing Framework for web applications. However, you are able to use the standard Go's `net/http/httptest` package as well but in this example we will use the `kataras/iris/httptest`.
-
-```go
-package main
-
-import (
-    "fmt"
-    "testing"
-
-    "github.com/kataras/iris/httptest"
-)
-
-// go test -v -run=TestCookiesBasic$
-func TestCookiesBasic(t *testing.T) {
-    app := newApp()
-    e := httptest.New(t, app, httptest.URL("http://example.com"))
-
-    cookieName, cookieValue := "my_cookie_name", "my_cookie_value"
-
-    // Test Set A Cookie.
-    t1 := e.GET(fmt.Sprintf("/cookies/%s/%s", cookieName, cookieValue)).Expect().Status(httptest.StatusOK)
-    t1.Cookie(cookieName).Value().Equal(cookieValue) // validate cookie's existence, it should be there now.
-    t1.Body().Contains(cookieValue)
-
-    path := fmt.Sprintf("/cookies/%s", cookieName)
-
-    // Test Retrieve A Cookie.
-    t2 := e.GET(path).Expect().Status(httptest.StatusOK)
-    t2.Body().Equal(cookieValue)
-
-    // Test Remove A Cookie.
-    t3 := e.DELETE(path).Expect().Status(httptest.StatusOK)
-    t3.Body().Contains(cookieName)
-
-    t4 := e.GET(path).Expect().Status(httptest.StatusOK)
-    t4.Cookies().Empty()
-    t4.Body().Empty()
-}
-```
-
-## Learn
-
-First of all, the most correct way to begin with a web framework is to learn the basics of the programming language and the standard `http` capabilities, if your web application is a very simple personal project without performance and maintainability requirements you may want to proceed just with the standard packages. After that follow the guidelines:
-
-- Navigate through **100+1** **[examples](_examples)** and some [iris starter kits](#iris-starter-kits) we crafted for you
-- Read the [godocs](https://godoc.org/github.com/kataras/iris) for any details
-- Prepare a cup of coffee or tea, whatever pleases you the most, and read some [articles](#articles) we found for you
-- Run some of our [starter kits](#iris-starter-kits)
-
-### Middleware
-
-Iris has a great collection of handlers[[1]](middleware/)[[2]](https://github.com/iris-contrib/middleware) that you can use side by side with your web apps. However you are not limited to them - you are free to use any third-party middleware that is compatible with the [net/http](https://golang.org/pkg/net/http/) package, [_examples/convert-handlers](_examples/convert-handlers) will show you the way.
-
-Iris, unlike others, is 100% compatible with the standards and that's why the majority of the big companies that adapt Go to their workflow, like a very famous US Television Network, trust Iris; it's up-to-date and it will be always aligned with the std `net/http` package which is modernized by the Go Authors on each new release of the Go Programming Language.
-
-### Video Courses
-
-| Description | Link | Author | Year |
-| -----------|-------------|-------------|-----|
-| Installing Iris | https://bit.ly/2KhgB1J | WarnabiruTV | 2018 |
-| Iris & Mongo DB Complete | https://bit.ly/2IcXZOu | Musobar Media | 2018 |
-| Quick Start with Iris | https://bit.ly/2wQIrJw | J-Secur1ty | **2019** |
-| Getting Started with Iris | https://bit.ly/2XGafMv | stephgdesign | 2018 |
-
-### Articles
-
-* [A URL Shortener Service using Go, Iris and Bolt (Updated)](https://bit.ly/2KeP6pE)
-* [CRUD REST API in Iris (a framework for golang)](https://bit.ly/2X9EsXl)
-* [A Todo MVC Application using Iris and Vue.js](https://bit.ly/2KgEarI)
-* [A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](https://bit.ly/2Kfdsjf)
-* [Top 6 web frameworks for Go as of 2017](https://bit.ly/2wMi9YY)
-* [Iris Go Framework + MongoDB](https://bit.ly/2WDOsZF)
-* [How to build a file upload form using DropzoneJS and Go](https://bit.ly/2IdigmZ)
-* [How to display existing files on server using DropzoneJS and Go](https://bit.ly/2IBQ7Vv)
-* [Iris, a modular web framework](https://bit.ly/2KHm6q0)
-* [Go vs .NET Core in terms of HTTP performance](https://bit.ly/2Kh7ezl)
-* [Iris Go vs .NET Core Kestrel in terms of HTTP performance](https://bit.ly/2WBqucu)
-* [How to Turn an Android Device into a Web Server](https://bit.ly/2Icl5EM)
-
-## Iris starter kits
-
-1. [snowlyg/IrisApiProject: Iris + gorm + jwt + sqlite3](https://bit.ly/2IaL1R6) **NEW-Chinese**
-2. [yz124/superstar: Iris + xorm to implement the star library](https://bit.ly/2WF4ZfK) **NEW-Chinese**
-3. [jebzmos4/Iris-golang: A basic CRUD API in golang with Iris](https://bit.ly/2XFyESo)
-4. [gauravtiwari/go_iris_app: A basic web app built in Iris for Go](https://bit.ly/2XFVYQ4)
-5. [A mini social-network created with the awesome Iris💖💖](https://bit.ly/2KJvZn7)
-6. [Iris isomorphic react/hot reloadable/redux/css-modules starter kit](https://bit.ly/2ReoGoH)
-7. [ionutvilie/react-ts: Demo project with react using typescript and Iris](https://bit.ly/2wZA52B)
-8. [Self-hosted Localization Management Platform built with Iris and Angular](https://bit.ly/2F9iYzM)
-9. [Iris + Docker and Kubernetes](https://bit.ly/2WGlXKL)
-10. [nanobox.io: Quickstart for Iris with Nanobox](https://bit.ly/2wMkdjG)
-11. [hasura.io: A Hasura starter project with a ready to deploy Golang hello-world web app with IRIS](https://bit.ly/2Kfdsjf)
-
-## Support
-
-- [HISTORY](HISTORY.md#fr-11-january-2019--v1111) file is your best friend, it contains information about the latest features and changes
-- Did you happen to find a bug? Post it at [github issues](https://github.com/kataras/iris/issues)
-- Do you have any questions or need to speak with someone experienced to solve a problem at real-time? Join us to the [community chat](https://chat.iris-go.com)
-- Complete our form-based user experience report by clicking [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
-- Do you like the framework? Tweet something about it! The People have spoken:
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
-
- 
-    
-
-
 ### Get hired
 
 There are many companies and start-ups looking for Go web developers with Iris experience as requirement, we are searching for you every day and we post those information via our [facebook page](https://www.facebook.com/iris.framework), like the page to get notified, we have already posted some of them.
@@ -1073,18 +64,6 @@ Gerasimos Maropoulos
  
 
 
-### Backers
-
-Thank you to all our backers! 🙏 [Become a backer](https://iris-go.com/donate)
-
-
-
-

- -For more information about contributing to the Iris project please check the [CONTRIBUTING.md](CONTRIBUTING.md) file. - -[List of all Contributors](https://github.com/kataras/iris/graphs/contributors) - ## License Iris is licensed under the [3-Clause BSD License](LICENSE). Iris is 100% free and open-source software. diff --git a/_examples/websocket/basic/server.go b/_examples/websocket/basic/server.go index 230ecf20..f71a49a6 100644 --- a/_examples/websocket/basic/server.go +++ b/_examples/websocket/basic/server.go @@ -7,8 +7,7 @@ import ( "github.com/kataras/iris/websocket" // Used when "enableJWT" constant is true: - "github.com/dgrijalva/jwt-go" - jwtmiddleware "github.com/iris-contrib/middleware/jwt" + "github.com/iris-contrib/middleware/jwt" ) // values should match with the client sides as well. @@ -50,17 +49,22 @@ func main() { websocket.DefaultGorillaUpgrader, /* DefaultGobwasUpgrader can be used too. */ serverEvents) - j := jwtmiddleware.New(jwtmiddleware.Config{ + j := jwt.New(jwt.Config{ // Extract by the "token" url, // so the client should dial with ws://localhost:8080/echo?token=$token - Extractor: jwtmiddleware.FromParameter("token"), + Extractor: jwt.FromParameter("token"), ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { return []byte("My Secret"), nil }, - // When set, the middleware verifies that tokens are signed with the specific signing algorithm - // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks - // Important to avoid security issues described here: https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ + + // When set, the middleware verifies that tokens are signed + // with the specific signing algorithm + // If the signing method is not constant the + // `Config.ValidationKeyGetter` callback field can be used + // to implement additional checks + // Important to avoid security issues described here: + // https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ SigningMethod: jwt.SigningMethodHS256, }) diff --git a/cache/cache.go b/cache/cache.go index 645d6313..1ba55a68 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -34,31 +34,23 @@ import ( "github.com/kataras/iris/context" ) -// Cache accepts the cache expiration duration -// if the expiration <=2 seconds then expiration is taken by the "cache-control's maxage" header -// returns context.Handler, which you can use as your default router or per-route handler +// Cache accepts the cache expiration duration. +// If the "expiration" input argument is invalid, <=2 seconds, +// then expiration is taken by the "cache-control's maxage" header. +// Returns a Handler structure which you can use to customize cache furher. // // All types of response can be cached, templates, json, text, anything. // // Use it for server-side caching, see the `iris#Cache304` for an alternative approach that -// may fit your needs most. +// may be more suited to your needs. // // You can add validators with this function. func Cache(expiration time.Duration) *client.Handler { return client.NewHandler(expiration) } -// Handler accepts one single parameter: -// the cache expiration duration -// if the expiration <=2 seconds then expiration is taken by the "cache-control's maxage" header -// returns context.Handler. -// -// All types of response can be cached, templates, json, text, anything. -// -// Use it for server-side caching, see the `iris#Cache304` for an alternative approach that -// may fit your needs most. -// -// it returns a context.Handler which can be used as a middleware, for more options use the `Cache`. +// Handler like `Cache` but returns an Iris Handler to be used as a middleware. +// For more options use the `Cache`. // // Examples can be found at: https://github.com/kataras/iris/tree/master/_examples/#caching func Handler(expiration time.Duration) context.Handler { diff --git a/context/context.go b/context/context.go index bab70562..aa76f9f5 100644 --- a/context/context.go +++ b/context/context.go @@ -658,8 +658,9 @@ type Context interface { // // It's mostly used internally on core/router/fs.go and context methods. WriteNotModified() - // WriteWithExpiration like Write but it sends with an expiration datetime - // which is refreshed every package-level `StaticCacheDuration` field. + // WriteWithExpiration works like `Write` but it will check if a resource is modified, + // based on the "modtime" input argument, + // otherwise sends a 304 status code in order to let the client-side render the cached content. WriteWithExpiration(body []byte, modtime time.Time) (int, error) // StreamWriter registers the given stream writer for populating // response body. @@ -1672,10 +1673,10 @@ type ( } // ReferrerType is the goreferrer enum for a referrer type (indirect, direct, email, search, social). - ReferrerType int + ReferrerType = goreferrer.ReferrerType // ReferrerGoogleSearchType is the goreferrer enum for a google search type (organic, adwords). - ReferrerGoogleSearchType int + ReferrerGoogleSearchType = goreferrer.GoogleSearchType ) // Contains the available values of the goreferrer enums. @@ -1692,14 +1693,6 @@ const ( ReferrerGoogleAdwords ) -func (gs ReferrerGoogleSearchType) String() string { - return goreferrer.GoogleSearchType(gs).String() -} - -func (r ReferrerType) String() string { - return goreferrer.ReferrerType(r).String() -} - // unnecessary but good to know the default values upfront. var emptyReferrer = Referrer{Type: ReferrerInvalid, GoogleType: ReferrerNotGoogleSearch} @@ -2584,8 +2577,9 @@ func (ctx *context) WriteNotModified() { ctx.StatusCode(http.StatusNotModified) } -// WriteWithExpiration like Write but it sends with an expiration datetime -// which is refreshed every package-level `StaticCacheDuration` field. +// WriteWithExpiration works like `Write` but it will check if a resource is modified, +// based on the "modtime" input argument, +// otherwise sends a 304 status code in order to let the client-side render the cached content. func (ctx *context) WriteWithExpiration(body []byte, modtime time.Time) (int, error) { if modified, err := ctx.CheckIfModifiedSince(modtime); !modified && err == nil { ctx.WriteNotModified() diff --git a/doc.go b/doc.go index 840e87e5..ae5417e6 100644 --- a/doc.go +++ b/doc.go @@ -44,1756 +44,11 @@ Installation The only requirement is the Go Programming Language, at least version 1.12. - $ go get -u github.com/kataras/iris + $ go get github.com/kataras/iris@v11.2.0 +Wiki: -Example code: - - - package main - - import "github.com/kataras/iris" - - // User is just a bindable object structure. - type User struct { - Username string `json:"username"` - Firstname string `json:"firstname"` - Lastname string `json:"lastname"` - City string `json:"city"` - Age int `json:"age"` - } - - func main() { - app := iris.New() - - // Define templates using the std html/template engine. - // Parse and load all files inside "./views" folder with ".html" file extension. - // Reload the templates on each request (development mode). - app.RegisterView(iris.HTML("./views", ".html").Reload(true)) - - // Register custom handler for specific http errors. - app.OnErrorCode(iris.StatusInternalServerError, func(ctx iris.Context) { - // .Values are used to communicate between handlers, middleware. - errMessage := ctx.Values().GetString("error") - if errMessage != "" { - ctx.Writef("Internal server error: %s", errMessage) - return - } - - ctx.Writef("(Unexpected) internal server error") - }) - - app.Use(func(ctx iris.Context) { - ctx.Application().Logger().Infof("Begin request for path: %s", ctx.Path()) - ctx.Next() - }) - - // app.Done(func(ctx iris.Context) {}) - - // Method POST: http://localhost:8080/decode - app.Post("/decode", func(ctx iris.Context) { - var user User - ctx.ReadJSON(&user) - ctx.Writef("%s %s is %d years old and comes from %s", user.Firstname, user.Lastname, user.Age, user.City) - }) - - // Method GET: http://localhost:8080/encode - app.Get("/encode", func(ctx iris.Context) { - doe := User{ - Username: "Johndoe", - Firstname: "John", - Lastname: "Doe", - City: "Neither FBI knows!!!", - Age: 25, - } - - ctx.JSON(doe) - }) - - // Method GET: http://localhost:8080/profile/anytypeofstring - app.Get("/profile/{username:string}", profileByUsername) - - // Want to use a custom regex expression instead? - // Easy: app.Get("/profile/{username:string regexp(^[a-zA-Z ]+$)}") - // - // If parameter type is missing then it's string which accepts anything, - // i.e: /{paramname} it's exactly the same as /{paramname:string}. - - usersRoutes := app.Party("/users", logThisMiddleware) - { - // Method GET: http://localhost:8080/users/42 - usersRoutes.Get("/{id:uint64 min(1)}", getUserByID) - // Method POST: http://localhost:8080/users/create - usersRoutes.Post("/create", createUser) - } - - // Listen for incoming HTTP/1.x & HTTP/2 clients on localhost port 8080. - app.Run(iris.Addr(":8080"), iris.WithCharset("UTF-8")) - } - - func logThisMiddleware(ctx iris.Context) { - ctx.Application().Logger().Infof("Path: %s | IP: %s", ctx.Path(), ctx.RemoteAddr()) - - // .Next is required to move forward to the chain of handlers, - // if missing then it stops the execution at this handler. - ctx.Next() - } - - func profileByUsername(ctx iris.Context) { - // .Params are used to get dynamic path parameters. - username := ctx.Params().Get("username") - ctx.ViewData("Username", username) - // renders "./views/users/profile.html" - // with {{ .Username }} equals to the username dynamic path parameter. - ctx.View("users/profile.html") - } - - func getUserByID(ctx iris.Context) { - userID := ctx.Params().Get("id") // Or convert directly using: .Values().GetInt/GetUint64/GetInt64 etc... - // your own db fetch here instead of user :=... - user := User{Username: "username" + userID} - - ctx.XML(user) - } - - func createUser(ctx iris.Context) { - var user User - err := ctx.ReadForm(&user) - if err != nil { - ctx.Values().Set("error", "creating user, read and parse form failed. "+err.Error()) - ctx.StatusCode(iris.StatusInternalServerError) - return - } - // renders "./views/users/create_verification.html" - // with {{ . }} equals to the User object, i.e {{ .Username }} , {{ .Firstname}} etc... - ctx.ViewData("", user) - ctx.View("users/create_verification.html") - } - -Listening and gracefully shutdown - -You can start the server(s) listening to any type of `net.Listener` or even `http.Server` instance. -The method for initialization of the server should be passed at the end, via `Run` function. - -Below you'll see some useful examples: - - - // Listening on tcp with network address 0.0.0.0:8080 - app.Run(iris.Addr(":8080")) - - - // Same as before but using a custom http.Server which may be in use somewhere else too - app.Run(iris.Server(&http.Server{Addr:":8080"})) - - - // Using a custom net.Listener - l, err := net.Listen("tcp4", ":8080") - if err != nil { - panic(err) - } - app.Run(iris.Listener(l)) - - - // TLS using files - app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key")) - - - // Automatic TLS - app.Run(iris.AutoTLS(":443", "example.com", "admin@example.com")) - - - // UNIX socket - if errOs := os.Remove(socketFile); errOs != nil && !os.IsNotExist(errOs) { - app.Logger().Fatal(errOs) - } - - l, err := net.Listen("unix", socketFile) - - if err != nil { - app.Logger().Fatal(err) - } - - if err = os.Chmod(socketFile, mode); err != nil { - app.Logger().Fatal(err) - } - - app.Run(iris.Listener(l)) - - // Using any func() error, - // the responsibility of starting up a listener is up to you with this way, - // for the sake of simplicity we will use the - // ListenAndServe function of the `net/http` package. - app.Run(iris.Raw(&http.Server{Addr:":8080"}).ListenAndServe) - -UNIX and BSD hosts can take advantage of the reuse port feature. - -Example code: - - - package main - - import ( - // Package tcplisten provides customizable TCP net.Listener with various - // performance-related options: - // - // - SO_REUSEPORT. This option allows linear scaling server performance - // on multi-CPU servers. - // See https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ for details. - // - // - TCP_DEFER_ACCEPT. This option expects the server reads from the accepted - // connection before writing to them. - // - // - TCP_FASTOPEN. See https://lwn.net/Articles/508865/ for details. - "github.com/valyala/tcplisten" - - "github.com/kataras/iris" - ) - - // $ go get github.com/valyala/tcplisten - // $ go run main.go - - func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("Hello World!") - }) - - listenerCfg := tcplisten.Config{ - ReusePort: true, - DeferAccept: true, - FastOpen: true, - } - - l, err := listenerCfg.NewListener("tcp", ":8080") - if err != nil { - panic(err) - } - - app.Run(iris.Listener(l)) - } - -That's all with listening, you have the full control when you need it. - -Let's continue by learning how to catch CONTROL+C/COMMAND+C or unix kill command and shutdown the server gracefully. - - Gracefully Shutdown on CONTROL+C/COMMAND+C or when kill command sent is ENABLED BY-DEFAULT. - -In order to manually manage what to do when app is interrupted, -we have to disable the default behavior with the option `WithoutInterruptHandler` -and register a new interrupt handler (globally, across all possible hosts). - - -Example code: - - - package main - - import ( - stdContext "context" - "time" - - "github.com/kataras/iris" - ) - - - func main() { - app := iris.New() - - iris.RegisterOnInterrupt(func() { - timeout := 5 * time.Second - ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout) - defer cancel() - // close all hosts - app.Shutdown(ctx) - }) - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

hi, I just exist in order to see if the server is closed

") - }) - - // http://localhost:8080 - app.Run(iris.Addr(":8080"), iris.WithoutInterruptHandler) - } - - -Hosts - -Access to all hosts that serve your application can be provided by -the `Application#Hosts` field, after the `Run` method. - - -But the most common scenario is that you may need access to the host before the `Run` method, -there are two ways of gain access to the host supervisor, read below. - -First way is to use the `app.NewHost` to create a new host -and use one of its `Serve` or `Listen` functions -to start the application via the `iris#Raw` Runner. -Note that this way needs an extra import of the `net/http` package. - -Example Code: - - - h := app.NewHost(&http.Server{Addr:":8080"}) - h.RegisterOnShutdown(func(){ - println("terminate") - }) - - app.Run(iris.Raw(h.ListenAndServe)) - -Second, and probably easier way is to use the `host.Configurator`. - -Note that this method requires an extra import statement of -"github.com/kataras/iris/core/host" when using go < 1.9, -if you're targeting on go1.9 then you can use the `iris#Supervisor` -and omit the extra host import. - -All common `Runners` we saw earlier (`iris#Addr, iris#Listener, iris#Server, iris#TLS, iris#AutoTLS`) -accept a variadic argument of `host.Configurator`, there are just `func(*host.Supervisor)`. -Therefore the `Application` gives you the rights to modify the auto-created host supervisor through these. - - -Example Code: - - - package main - - import ( - stdContext "context" - "time" - - "github.com/kataras/iris" - "github.com/kataras/iris/core/host" - ) - - func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.HTML("

Hello, try to refresh the page after ~10 secs

") - }) - - app.Logger().Info("Wait 10 seconds and check your terminal again") - // simulate a shutdown action here... - go func() { - <-time.After(10 * time.Second) - timeout := 5 * time.Second - ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout) - defer cancel() - // close all hosts, this will notify the callback we had register - // inside the `configureHost` func. - app.Shutdown(ctx) - }() - - // start the server as usual, the only difference is that - // we're adding a second (optional) function - // to configure the just-created host supervisor. - // - // http://localhost:8080 - // wait 10 seconds and check your terminal. - app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed)) - - } - - func configureHost(su *host.Supervisor) { - // here we have full access to the host that will be created - // inside the `Run` function. - // - // we register a shutdown "event" callback - su.RegisterOnShutdown(func() { - println("terminate") - }) - // su.RegisterOnError - // su.RegisterOnServe - } - - -Read more about listening and gracefully shutdown by navigating to: - - https://github.com/kataras/iris/tree/master/_examples/#http-listening - - -Routing - -All HTTP methods are supported, developers can also register handlers for same paths for different methods. -The first parameter is the HTTP Method, -second parameter is the request path of the route, -third variadic parameter should contains one or more iris.Handler executed -by the registered order when a user requests for that specific resouce path from the server. - -Example code: - - - app := iris.New() - - app.Handle("GET", "/contact", func(ctx iris.Context) { - ctx.HTML("

Hello from /contact

") - }) - - -In order to make things easier for the user, iris provides functions for all HTTP Methods. -The first parameter is the request path of the route, -second variadic parameter should contains one or more iris.Handler executed -by the registered order when a user requests for that specific resouce path from the server. - -Example code: - - - app := iris.New() - - // Method: "GET" - app.Get("/", handler) - - // Method: "POST" - app.Post("/", handler) - - // Method: "PUT" - app.Put("/", handler) - - // Method: "DELETE" - app.Delete("/", handler) - - // Method: "OPTIONS" - app.Options("/", handler) - - // Method: "TRACE" - app.Trace("/", handler) - - // Method: "CONNECT" - app.Connect("/", handler) - - // Method: "HEAD" - app.Head("/", handler) - - // Method: "PATCH" - app.Patch("/", handler) - - // register the route for all HTTP Methods - app.Any("/", handler) - - func handler(ctx iris.Context){ - ctx.Writef("Hello from method: %s and path: %s", ctx.Method(), ctx.Path()) - } - - - -Grouping Routes - - -A set of routes that are being groupped by path prefix can (optionally) share the same middleware handlers and template layout. -A group can have a nested group too. - -`.Party` is being used to group routes, developers can declare an unlimited number of (nested) groups. - - -Example code: - - - users := app.Party("/users", myAuthMiddlewareHandler) - - // http://myhost.com/users/42/profile - users.Get("/{id:uint64}/profile", userProfileHandler) - // http://myhost.com/users/messages/1 - users.Get("/messages/{id:int}", userMessageHandler) - - -Custom HTTP Errors - - -iris developers are able to register their own handlers for http statuses like 404 not found, 500 internal server error and so on. - -Example code: - - - // when 404 then render the template $templatedir/errors/404.html - app.OnErrorCode(iris.StatusNotFound, func(ctx iris.Context){ - ctx.View("errors/404.html") - }) - - app.OnErrorCode(500, func(ctx iris.Context){ - // ... - }) - -Basic HTTP API - -With the help of iris's expressionist router you can build any form of API you desire, with -safety. - -Example code: - - - package main - - import "github.com/kataras/iris" - - func main() { - app := iris.New() - - // registers a custom handler for 404 not found http (error) status code, - // fires when route not found or manually by ctx.StatusCode(iris.StatusNotFound). - app.OnErrorCode(iris.StatusNotFound, notFoundHandler) - - // GET -> HTTP Method - // / -> Path - // func(ctx iris.Context) -> The route's handler. - // - // Third receiver should contains the route's handler(s), they are executed by order. - app.Handle("GET", "/", func(ctx iris.Context) { - // navigate to the middle of $GOPATH/src/github.com/kataras/iris/context/context.go - // to overview all context's method (there a lot of them, read that and you will learn how iris works too) - ctx.HTML("Hello from " + ctx.Path()) // Hello from / - }) - - app.Get("/home", func(ctx iris.Context) { - ctx.Writef(`Same as app.Handle("GET", "/", [...])`) - }) - - app.Get("/donate", donateHandler, donateFinishHandler) - - // Pssst, don't forget dynamic-path example for more "magic"! - app.Get("/api/users/{userid:uint64 min(1)}", func(ctx iris.Context) { - userID, err := ctx.Params().GetUint64("userid") - - if err != nil { - ctx.Writef("error while trying to parse userid parameter," + - "this will never happen if :int is being used because if it's not integer it will fire Not Found automatically.") - ctx.StatusCode(iris.StatusBadRequest) - return - } - - ctx.JSON(map[string]interface{}{ - // you can pass any custom structured go value of course. - "user_id": userID, - }) - }) - // app.Post("/", func(ctx iris.Context){}) -> for POST http method. - // app.Put("/", func(ctx iris.Context){})-> for "PUT" http method. - // app.Delete("/", func(ctx iris.Context){})-> for "DELETE" http method. - // app.Options("/", func(ctx iris.Context){})-> for "OPTIONS" http method. - // app.Trace("/", func(ctx iris.Context){})-> for "TRACE" http method. - // app.Head("/", func(ctx iris.Context){})-> for "HEAD" http method. - // app.Connect("/", func(ctx iris.Context){})-> for "CONNECT" http method. - // app.Patch("/", func(ctx iris.Context){})-> for "PATCH" http method. - // app.Any("/", func(ctx iris.Context){}) for all http methods. - - // More than one route can contain the same path with a different http mapped method. - // You can catch any route creation errors with: - // route, err := app.Get(...) - // set a name to a route: route.Name = "myroute" - - // You can also group routes by path prefix, sharing middleware(s) and done handlers. - - adminRoutes := app.Party("/admin", adminMiddleware) - - adminRoutes.Done(func(ctx iris.Context) { // executes always last if ctx.Next() - ctx.Application().Logger().Infof("response sent to " + ctx.Path()) - }) - // adminRoutes.Layout("/views/layouts/admin.html") // set a view layout for these routes, see more at view examples. - - // GET: http://localhost:8080/admin - adminRoutes.Get("/", func(ctx iris.Context) { - // [...] - ctx.StatusCode(iris.StatusOK) // default is 200 == iris.StatusOK - ctx.HTML("

Hello from admin/

") - - ctx.Next() // in order to execute the party's "Done" Handler(s) - }) - - // GET: http://localhost:8080/admin/login - adminRoutes.Get("/login", func(ctx iris.Context) { - // [...] - }) - // POST: http://localhost:8080/admin/login - adminRoutes.Post("/login", func(ctx iris.Context) { - // [...] - }) - - // subdomains, easier than ever, should add localhost or 127.0.0.1 into your hosts file, - // etc/hosts on unix or C:/windows/system32/drivers/etc/hosts on windows. - v1 := app.Party("v1.") - { // braces are optional, it's just type of style, to group the routes visually. - - // http://v1.localhost:8080 - v1.Get("/", func(ctx iris.Context) { - ctx.HTML("Version 1 API. go to /api/users") - }) - - usersAPI := v1.Party("/api/users") - { - // http://v1.localhost:8080/api/users - usersAPI.Get("/", func(ctx iris.Context) { - ctx.Writef("All users") - }) - // http://v1.localhost:8080/api/users/42 - usersAPI.Get("/{userid:uint64}", func(ctx iris.Context) { - ctx.Writef("user with id: %s", ctx.Params().GetUint64("userid")) - }) - } - } - - // wildcard subdomains. - wildcardSubdomain := app.Party("*.") - { - wildcardSubdomain.Get("/", func(ctx iris.Context) { - ctx.Writef("Subdomain can be anything, now you're here from: %s", ctx.Subdomain()) - }) - } - - // http://localhost:8080 - // http://localhost:8080/home - // http://localhost:8080/donate - // http://localhost:8080/api/users/42 - // http://localhost:8080/admin - // http://localhost:8080/admin/login - // - // http://localhost:8080/api/users/0 - // http://localhost:8080/api/users/blabla - // http://localhost:8080/wontfound - // - // if hosts edited: - // http://v1.localhost:8080 - // http://v1.localhost:8080/api/users - // http://v1.localhost:8080/api/users/42 - // http://anything.localhost:8080 - app.Run(iris.Addr(":8080")) - } - - func adminMiddleware(ctx iris.Context) { - // [...] - ctx.Next() // to move to the next handler, or don't that if you have any auth logic. - } - - func donateHandler(ctx iris.Context) { - ctx.Writef("Just like an inline handler, but it can be " + - "used by other package, anywhere in your project.") - - // let's pass a value to the next handler - // Values is the way handlers(or middleware) are communicating between each other. - ctx.Values().Set("donate_url", "https://github.com/kataras/iris#-people") - ctx.Next() // in order to execute the next handler in the chain, look donate route. - } - - func donateFinishHandler(ctx iris.Context) { - // values can be any type of object so we could cast the value to a string - // but iris provides an easy to do that, if donate_url is not defined, then it returns an empty string instead. - donateURL := ctx.Values().GetString("donate_url") - ctx.Application().Logger().Infof("donate_url value was: " + donateURL) - ctx.Writef("\n\nDonate sent(?).") - } - - func notFoundHandler(ctx iris.Context) { - ctx.HTML("Custom route for 404 not found http code, here you can render a view, html, json any valid response.") - } - - -Parameterized Path - -At the previous example, -we've seen static routes, group of routes, subdomains, wildcard subdomains, a small example of parameterized path -with a single known parameter and custom http errors, now it's time to see wildcard parameters and macros. - -iris, like net/http std package registers route's handlers -by a Handler, the iris' type of handler is just a func(ctx iris.Context) -where context comes from github.com/kataras/iris/context. - -Iris has the easiest and the most powerful routing process you have ever meet. - -At the same time, -iris has its own interpeter(yes like a programming language) -for route's path syntax and their dynamic path parameters parsing and evaluation, -We call them "macros" for shortcut. -How? It calculates its needs and if not any special regexp needed then it just -registers the route with the low-level path syntax, -otherwise it pre-compiles the regexp and adds the necessary middleware(s). - -Standard macro types for parameters: - - +------------------------+ - | {param:string} | - +------------------------+ - string type - anything (single path segmnent) - - +-------------------------------+ - | {param:int} | - +-------------------------------+ - int type - -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch - - +------------------------+ - | {param:int8} | - +------------------------+ - int8 type - -128 to 127 - - +------------------------+ - | {param:int16} | - +------------------------+ - int16 type - -32768 to 32767 - - +------------------------+ - | {param:int32} | - +------------------------+ - int32 type - -2147483648 to 2147483647 - - +------------------------+ - | {param:int64} | - +------------------------+ - int64 type - -9223372036854775808 to 9223372036854775807 - - +------------------------+ - | {param:uint} | - +------------------------+ - uint type - 0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32) - - +------------------------+ - | {param:uint8} | - +------------------------+ - uint8 type - 0 to 255 - - +------------------------+ - | {param:uint16} | - +------------------------+ - uint16 type - 0 to 65535 - - +------------------------+ - | {param:uint32} | - +------------------------+ - uint32 type - 0 to 4294967295 - - +------------------------+ - | {param:uint64} | - +------------------------+ - uint64 type - 0 to 18446744073709551615 - - +---------------------------------+ - | {param:bool} or {param:boolean} | - +---------------------------------+ - bool type - only "1" or "t" or "T" or "TRUE" or "true" or "True" - or "0" or "f" or "F" or "FALSE" or "false" or "False" - - +------------------------+ - | {param:alphabetical} | - +------------------------+ - alphabetical/letter type - letters only (upper or lowercase) - - +------------------------+ - | {param:file} | - +------------------------+ - file type - letters (upper or lowercase) - numbers (0-9) - underscore (_) - dash (-) - point (.) - no spaces ! or other character - - +------------------------+ - | {param:path} | - +------------------------+ - path type - anything, should be the last part, can be more than one path segment, - i.e: "/test/{param:path}" and request: "/test/path1/path2/path3" , ctx.Params().Get("param") == "path1/path2/path3" - -if type is missing then parameter's type is defaulted to string, so -{param} == {param:string}. - -If a function not found on that type then the "string"'s types functions are being used. -i.e: - - - {param:int min(3)} - - -Besides the fact that iris provides the basic types and some default "macro funcs" -you are able to register your own too!. - -Register a named path parameter function: - - - app.Macros().Get("int").RegisterFunc("min", func(argument int) func(paramValue int) bool { - return func(paramValue int) bool { - [...] - return true/false -> true means valid. - } - }) - -at the func(argument ...) you can have any standard type, it will be validated before the server starts -so don't care about performance here, the only thing it runs at serve time is the returning func(paramValue string) bool. - - {param:string equal(iris)} , "iris" will be the argument here: - app.Macros().Get("string").RegisterFunc("equal", func(argument string) func(paramValue string) bool { - return func(paramValue string){ return argument == paramValue } - }) - - -Example Code: - - - // you can use the "string" type which is valid for a single path parameter that can be anything. - app.Get("/username/{name}", func(ctx iris.Context) { - ctx.Writef("Hello %s", ctx.Params().Get("name")) - }) // type is missing = {name:string} - - // Let's register our first macro attached to int macro type. - // "min" = the function - // "minValue" = the argument of the function - // func() bool = the macro's path parameter evaluator, this executes in serve time when - // a user requests a path which contains the int macro type with the min(...) macro parameter function. - app.Macros().Get("int").RegisterFunc("min", func(minValue int) func(int) bool { - // do anything before serve here [...] - // at this case we don't need to do anything - return func(paramValue int) bool { - return paramValue >= minValue - } - }) - - // http://localhost:8080/profile/id>=1 - // this will throw 404 even if it's found as route on : /profile/0, /profile/blabla, /profile/-1 - // macro parameter functions are optional of course. - app.Get("/profile/{id:uint64 min(1)}", func(ctx iris.Context) { - // second parameter is the error but it will always nil because we use macros, - // the validaton already happened. - id, _ := ctx.Params().GetUint64("id") - ctx.Writef("Hello id: %d", id) - }) - - // to change the error code per route's macro evaluator: - app.Get("/profile/{id:uint64 min(1)}/friends/{friendid:uint64 min(1) else 504}", func(ctx iris.Context) { - id, _ := ctx.Params().GetUint64("id") - friendid, _ := ctx.Params().GetUint64("friendid") - ctx.Writef("Hello id: %d looking for friend id: ", id, friendid) - }) // this will throw e 504 error code instead of 404 if all route's macros not passed. - - // http://localhost:8080/game/a-zA-Z/level/42 - // remember, alphabetical is lowercase or uppercase letters only. - app.Get("/game/{name:alphabetical}/level/{level:int}", func(ctx iris.Context) { - ctx.Writef("name: %s | level: %s", ctx.Params().Get("name"), ctx.Params().Get("level")) - }) - - // let's use a trivial custom regexp that validates a single path parameter - // which its value is only lowercase letters. - - // http://localhost:8080/lowercase/anylowercase - app.Get("/lowercase/{name:string regexp(^[a-z]+)}", func(ctx iris.Context) { - ctx.Writef("name should be only lowercase, otherwise this handler will never executed: %s", ctx.Params().Get("name")) - }) - - // http://localhost:8080/single_file/app.js - app.Get("/single_file/{myfile:file}", func(ctx iris.Context) { - ctx.Writef("file type validates if the parameter value has a form of a file name, got: %s", ctx.Params().Get("myfile")) - }) - - // http://localhost:8080/myfiles/any/directory/here/ - // this is the only macro type that accepts any number of path segments. - app.Get("/myfiles/{directory:path}", func(ctx iris.Context) { - ctx.Writef("path type accepts any number of path segments, path after /myfiles/ is: %s", ctx.Params().Get("directory")) - }) - - app.Run(iris.Addr(":8080")) -} - - -Last, do not confuse ctx.Values() with ctx.Params(). -Path parameter's values goes to ctx.Params() and context's local storage -that can be used to communicate between handlers and middleware(s) goes to -ctx.Values(), path parameters and the rest of any custom values are separated for your own good. - -Run - - $ go run main.go - - - -Static Files - - - // HandleDir registers a handler that serves HTTP requests - // with the contents of a file system (physical or embedded). - // - // first parameter : the route path - // second parameter : the system or the embedded directory that needs to be served - // third parameter : not required, the directory options, set fields is optional. - // - // for more options look router.FileServer. - // - // api.HandleDir("/static", "./assets", DirOptions {ShowList: true, Gzip: true, IndexName: "index.html"}) - // - // Returns the GET *Route. - HandleDir(requestPath, directory string, opts ...DirOptions) (getRoute *Route) - - -Example code: - - - package main - - import "github.com/kataras/iris" - - func main() { - app := iris.New() - - app.Favicon("./assets/favicon.ico") - - // first parameter is the request path - // second is the system directory - // - // app.HandleDir("/css", "./assets/css") - // app.HandleDir("/js", "./assets/js") - - app.HandleDir("/static", "./assets", iris.DirOptions{ - // Defaults to "/index.html", if request path is ending with IndexName - // then it redirects to ../ which another handler is handling it, - // that another handler, called index handler, is auto-registered by the framework - // if end developer does not managed to handle it by hand. - IndexName: "/index.html", - // When files should served under compression. - Gzip: false, - // List the files inside the current requested directory if `IndexName` not found. - ShowList: false, - // If `ShowList` is true then this function will be used instead of the default one to show the list of files of a current requested directory(dir). - // DirList: func(ctx context.Context, dirName string, dir http.File) error { ... } - // - // Optional validator that loops through each requested resource. - // AssetValidator: func(ctx iris.Context, name string) bool { ... } - }) - // You can also register any index handler manually, order of registration does not matter: - // app.Get("/static", [...custom middleware...], func(ctx iris.Context) { - // [...custom code...] - // ctx.ServeFile("./assets/index.html", false) - // }) - - // http://localhost:8080/static - // http://localhost:8080/static/css/main.css - // http://localhost:8080/static/js/jquery-2.1.1.js - // http://localhost:8080/static/favicon.ico - app.Run(iris.Addr(":8080")) - } - -More examples can be found here: https://github.com/kataras/iris/tree/master/_examples/beginner/file-server - - -Middleware Ecosystem - -Middleware is just a concept of ordered chain of handlers. -Middleware can be registered globally, per-party, per-subdomain and per-route. - - -Example code: - - // globally - // before any routes, appends the middleware to all routes - app.Use(func(ctx iris.Context){ - // ... any code here - - ctx.Next() // in order to continue to the next handler, - // if that is missing then the next in chain handlers will be not executed, - // useful for authentication middleware - }) - - // globally - // after or before any routes, prepends the middleware to all routes - app.UseGlobal(handler1, handler2, handler3) - - // per-route - app.Post("/login", authenticationHandler, loginPageHandler) - - // per-party(group of routes) - users := app.Party("/users", usersMiddleware) - users.Get("/", usersIndex) - - // per-subdomain - mysubdomain := app.Party("mysubdomain.", firstMiddleware) - mysubdomain.Use(secondMiddleware) - mysubdomain.Get("/", mysubdomainIndex) - - // per wildcard, dynamic subdomain - dynamicSub := app.Party(".*", firstMiddleware, secondMiddleware) - dynamicSub.Get("/", func(ctx iris.Context){ - ctx.Writef("Hello from subdomain: "+ ctx.Subdomain()) - }) - - -iris is able to wrap and convert any external, third-party Handler you used to use to your web application. -Let's convert the https://github.com/rs/cors net/http external middleware which returns a `next form` handler. - - -Example code: - - package main - - import ( - "github.com/rs/cors" - - "github.com/kataras/iris" - ) - - func main() { - - app := iris.New() - corsOptions := cors.Options{ - AllowedOrigins: []string{"*"}, - AllowCredentials: true, - } - - corsWrapper := cors.New(corsOptions).ServeHTTP - - app.WrapRouter(corsWrapper) - - v1 := app.Party("/api/v1") - { - v1.Get("/", h) - v1.Put("/put", h) - v1.Post("/post", h) - } - - app.Run(iris.Addr(":8080")) - } - - func h(ctx iris.Context) { - ctx.Application().Logger().Infof(ctx.Path()) - ctx.Writef("Hello from %s", ctx.Path()) - } - - -View Engine - - -Iris supports 6 template engines out-of-the-box, developers can still use any external golang template engine, -as `context/context#ResponseWriter()` is an `io.Writer`. - -All of these five template engines have common features with common API, -like Layout, Template Funcs, Party-specific layout, partial rendering and more. - - The standard html, - its template parser is the golang.org/pkg/html/template/ - - Django, - its template parser is the github.com/flosch/pongo2 - - Pug(Jade), - its template parser is the github.com/Joker/jade - - Handlebars, - its template parser is the github.com/aymerick/raymond - - Amber, - its template parser is the github.com/eknkc/amber - - Jet, - its template parser is the github.com/CloudyKit/jet - -Example code: - - package main - - import "github.com/kataras/iris" - - func main() { - app := iris.New() - - // - standard html | iris.HTML(...) - // - django | iris.Django(...) - // - pug(jade) | iris.Pug(...) - // - handlebars | iris.Handlebars(...) - // - amber | iris.Amber(...) - // - jet | iris.Jet(...) - - tmpl := iris.HTML("./templates", ".html") - tmpl.Reload(true) // reload templates on each request (development mode) - // default template funcs are: - // - // - {{ urlpath "mynamedroute" "pathParameter_ifneeded" }} - // - {{ render "header.html" }} - // - {{ render_r "header.html" }} // partial relative path to current page - // - {{ yield }} - // - {{ current }} - - // register a custom template func. - tmpl.AddFunc("greet", func(s string) string { - return "Greetings " + s + "!" - }) - - // register the view engine to the views, this will load the templates. - app.RegisterView(tmpl) - - app.Get("/", hi) - - // http://localhost:8080 - app.Run(iris.Addr(":8080"), iris.WithCharset("UTF-8")) // defaults to that but you can change it. - } - - func hi(ctx iris.Context) { - ctx.ViewData("Title", "Hi Page") - ctx.ViewData("Name", "iris") // {{.Name}} will render: iris - // ctx.ViewData("", myCcustomStruct{}) - ctx.View("hi.html") - } - - - -View engine supports bundled(https://github.com/shuLhan/go-bindata) template files too. -go-bindata gives you two functions, asset and assetNames, -these can be setted to each of the template engines using the `.Binary` func. - -Example code: - - package main - - import "github.com/kataras/iris" - - func main() { - app := iris.New() - // $ go get -u github.com/shuLhan/go-bindata/... - // $ go-bindata ./templates/... - // $ go build - // $ ./embedding-templates-into-app - // html files are not used, you can delete the folder and run the example - app.RegisterView(iris.HTML("./templates", ".html").Binary(Asset, AssetNames)) - app.Get("/", hi) - - // http://localhost:8080 - app.Run(iris.Addr(":8080")) - } - - type page struct { - Title, Name string - } - - func hi(ctx iris.Context) { - ctx.ViewData("", page{Title: "Hi Page", Name: "iris"}) - ctx.View("hi.html") - } - - -A real example can be found here: https://github.com/kataras/iris/tree/master/_examples/view/embedding-templates-into-app. - -Enable auto-reloading of templates on each request. Useful while developers are in dev mode -as they no neeed to restart their app on every template edit. - -Example code: - - - pugEngine := iris.Pug("./templates", ".jade") - pugEngine.Reload(true) // <--- set to true to re-build the templates on each request. - app.RegisterView(pugEngine) - -Note: - -In case you're wondering, the code behind the view engines derives from the "github.com/kataras/iris/view" package, -access to the engines' variables can be granded by "github.com/kataras/iris" package too. - - iris.HTML(...) is a shortcut of view.HTML(...) - iris.Django(...) >> >> view.Django(...) - iris.Pug(...) >> >> view.Pug(...) - iris.Handlebars(...) >> >> view.Handlebars(...) - iris.Amber(...) >> >> view.Amber(...) - iris.Jet(...) >> >> view.Jet(...) - -Each one of these template engines has different options located here: https://github.com/kataras/iris/tree/master/view . - - -Sessions - - -This example will show how to store and access data from a session. - -You don’t need any third-party library, -but If you want you can use any session manager compatible or not. - -In this example we will only allow authenticated users to view our secret message on the /secret page. -To get access to it, the will first have to visit /login to get a valid session cookie, -which logs him in. Additionally he can visit /logout to revoke his access to our secret message. - - -Example code: - - - // main.go - package main - - import ( - "github.com/kataras/iris" - - "github.com/kataras/iris/sessions" - ) - - var ( - cookieNameForSessionID = "mycookiesessionnameid" - sess = sessions.New(sessions.Config{Cookie: cookieNameForSessionID}) - ) - - func secret(ctx iris.Context) { - - // Check if user is authenticated - if auth, _ := sess.Start(ctx).GetBoolean("authenticated"); !auth { - ctx.StatusCode(iris.StatusForbidden) - return - } - - // Print secret message - ctx.WriteString("The cake is a lie!") - } - - func login(ctx iris.Context) { - session := sess.Start(ctx) - - // Authentication goes here - // ... - - // Set user as authenticated - session.Set("authenticated", true) - } - - func logout(ctx iris.Context) { - session := sess.Start(ctx) - - // Revoke users authentication - session.Set("authenticated", false) - } - - func main() { - app := iris.New() - - app.Get("/secret", secret) - app.Get("/login", login) - app.Get("/logout", logout) - - app.Run(iris.Addr(":8080")) - } - - -Running the example: - - - $ go get github.com/kataras/iris/sessions - $ go run main.go - - $ curl -s http://localhost:8080/secret - Forbidden - - $ curl -s -I http://localhost:8080/login - Set-Cookie: mycookiesessionnameid=MTQ4NzE5Mz... - - $ curl -s --cookie "mycookiesessionnameid=MTQ4NzE5Mz..." http://localhost:8080/secret - The cake is a lie! - - -Sessions persistence can be achieved using one (or more) `sessiondb`. - -Example Code: - - package main - - import ( - "time" - - "github.com/kataras/iris" - - "github.com/kataras/iris/sessions" - "github.com/kataras/iris/sessions/sessiondb/redis" - "github.com/kataras/iris/sessions/sessiondb/redis/service" - ) - - // tested with redis version 3.0.503. - // for windows see: https://github.com/ServiceStack/redis-windows - func main() { - // replace with your running redis' server settings: - db := redis.New(service.Config{ - Network: service.DefaultRedisNetwork, - Addr: service.DefaultRedisAddr, - Password: "", - Database: "", - MaxIdle: 0, - MaxActive: 0, - IdleTimeout: service.DefaultRedisIdleTimeout, - Prefix: ""}) // optionally configure the bridge between your redis server - - // close connection when control+C/cmd+C - iris.RegisterOnInterrupt(func() { - db.Close() - }) - - defer db.Close() // close the database connection if application errored. - - sess := sessions.New(sessions.Config{ - Cookie: "sessionscookieid", - Expires: 45 * time.Minute}, // <=0 means unlimited life. Defaults to 0. - ) - - // - // IMPORTANT: - // - sess.UseDatabase(db) - - // the rest of the code stays the same. - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.Writef("You should navigate to the /set, /get, /delete, /clear,/destroy instead") - }) - app.Get("/set", func(ctx iris.Context) { - s := sess.Start(ctx) - //set session values - s.Set("name", "iris") - - //test if setted here - ctx.Writef("All ok session value of the 'name' is: %s", s.GetString("name")) - }) - - app.Get("/set/{key}/{value}", func(ctx iris.Context) { - key, value := ctx.Params().Get("key"), ctx.Params().Get("value") - s := sess.Start(ctx) - // set session values - s.Set(key, value) - - // test if setted here - ctx.Writef("All ok session value of the '%s' is: %s", key, s.GetString(key)) - }) - - app.Get("/get", func(ctx iris.Context) { - // get a specific key, as string, if no found returns just an empty string - name := sess.Start(ctx).GetString("name") - - ctx.Writef("The 'name' on the /set was: %s", name) - }) - - app.Get("/get/{key}", func(ctx iris.Context) { - // get a specific key, as string, if no found returns just an empty string - name := sess.Start(ctx).GetString(ctx.Params().Get("key")) - - ctx.Writef("The name on the /set was: %s", name) - }) - - app.Get("/delete", func(ctx iris.Context) { - // delete a specific key - sess.Start(ctx).Delete("name") - }) - - app.Get("/clear", func(ctx iris.Context) { - // removes all entries - sess.Start(ctx).Clear() - }) - - app.Get("/destroy", func(ctx iris.Context) { - //destroy, removes the entire session data and cookie - sess.Destroy(ctx) - }) - - app.Get("/update", func(ctx iris.Context) { - // updates expire date with a new date - sess.ShiftExpiration(ctx) - }) - - app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed)) - } - - -More examples: - - https://github.com/kataras/iris/tree/master/_examples/sessions - - -Websockets - -In this example we will create a small chat between web sockets via browser. - -Example Server Code: - - // main.go - package main - - import ( - "fmt" - - "github.com/kataras/iris" - - "github.com/kataras/iris/websocket" - ) - - func main() { - app := iris.New() - - app.Get("/", func(ctx iris.Context) { - ctx.ServeFile("websockets.html", false) // second parameter: enable gzip? - }) - - setupWebsocket(app) - - // x2 - // http://localhost:8080 - // http://localhost:8080 - // write something, press submit, see the result. - app.Run(iris.Addr(":8080")) - } - - func setupWebsocket(app *iris.Application) { - // create our echo websocket server - ws := websocket.New(websocket.Config{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, - }) - ws.OnConnection(handleConnection) - - // register the server on an endpoint. - // see the inline javascript code i the websockets.html, this endpoint is used to connect to the server. - app.Get("/echo", ws.Handler()) - - // serve the javascript built-in client-side library, - // see websockets.html script tags, this path is used. - app.Any("/iris-ws.js", func(ctx iris.Context) { - ctx.Write(websocket.ClientSource) - }) - } - - func handleConnection(c websocket.Connection) { - // Read events from browser - c.On("chat", func(msg string) { - // Print the message to the console, c.Context() is the iris's http context. - fmt.Printf("%s sent: %s\n", c.Context().RemoteAddr(), msg) - // Write message back to the client message owner: - // c.Emit("chat", msg) - c.To(websocket.Broadcast).Emit("chat", msg) - }) - } - -Example Client(javascript) Code: - - - - -

-    
-    
-
-
-Running the example:
-
-
-    $ go get github.com/kataras/iris/websocket
-    $ go run main.go
-    $ start http://localhost:8080
-
-
-MVC - Model View Controller
-
-Iris has first-class support for the MVC pattern, you'll not find
-these stuff anywhere else in the Go world.
-
-Example Code:
-
-    package main
-
-    import (
-        "github.com/kataras/iris"
-        "github.com/kataras/iris/mvc"
-
-        "github.com/kataras/iris/middleware/logger"
-        "github.com/kataras/iris/middleware/recover"
-    )
-
-    func main() {
-        app := iris.New()
-        // Optionally, add two built-in handlers
-        // that can recover from any http-relative panics
-        // and log the requests to the terminal.
-        app.Use(recover.New())
-        app.Use(logger.New())
-
-        // Serve a controller based on the root Router, "/".
-        mvc.New(app).Handle(new(ExampleController))
-
-        // http://localhost:8080
-        // http://localhost:8080/ping
-        // http://localhost:8080/hello
-        // http://localhost:8080/custom_path
-        app.Run(iris.Addr(":8080"))
-    }
-
-    // ExampleController serves the "/", "/ping" and "/hello".
-    type ExampleController struct{}
-
-    // Get serves
-    // Method:   GET
-    // Resource: http://localhost:8080
-    func (c *ExampleController) Get() mvc.Result {
-        return mvc.Response{
-            ContentType: "text/html",
-            Text:        "

Welcome

", - } - } - - // GetPing serves - // Method: GET - // Resource: http://localhost:8080/ping - func (c *ExampleController) GetPing() string { - return "pong" - } - - // GetHello serves - // Method: GET - // Resource: http://localhost:8080/hello - func (c *ExampleController) GetHello() interface{} { - return map[string]string{"message": "Hello Iris!"} - } - - -// GetUserBy serves -// Method: GET -// Resource: http://localhost:8080/user/{username:string} -// By is a reserved "keyword" to tell the framework that you're going to -// bind path parameters in the function's input arguments, and it also -// helps to have "Get" and "GetBy" in the same controller. -// -// func (c *ExampleController) GetUserBy(username string) mvc.Result { -// return mvc.View{ -// Name: "user/username.html", -// Data: username, -// } -// } - -Can use more than one, the factory will make sure -that the correct http methods are being registered for each route -for this controller, uncomment these if you want: - - func (c *ExampleController) Post() {} - func (c *ExampleController) Put() {} - func (c *ExampleController) Delete() {} - func (c *ExampleController) Connect() {} - func (c *ExampleController) Head() {} - func (c *ExampleController) Patch() {} - func (c *ExampleController) Options() {} - func (c *ExampleController) Trace() {} -*/ -// -/* - func (c *ExampleController) All() {} - // OR - func (c *ExampleController) Any() {} - - func (c *ExampleController) BeforeActivation(b mvc.BeforeActivation) { - // 1 -> the HTTP Method - // 2 -> the route's path - // 3 -> this controller's method name that should be handler for that route. - b.Handle("GET", "/mypath/{param}", "DoIt", optionalMiddlewareHere...) - } - - // After activation, all dependencies are set-ed - so read only access on them - // but still possible to add custom controller or simple standard handlers. - func (c *ExampleController) AfterActivation(a mvc.AfterActivation) {} - - -Iris web framework supports Request data, Models, Persistence Data and Binding -with the fastest possible execution. - -Characteristics: - -All HTTP Methods are supported, for example if want to serve `GET` -then the controller should have a function named `Get()`, -you can define more than one method function to serve in the same Controller. - -Register custom controller's struct's methods as handlers with custom paths(even with regex parametermized path) -via the `BeforeActivation` custom event callback, per-controller. Example: - - package main - - import ( - "github.com/kataras/iris" - "github.com/kataras/iris/mvc" - ) - - func main() { - app := iris.New() - mvc.Configure(app.Party("/root"), myMVC) - app.Run(iris.Addr(":8080")) - } - - func myMVC(app *mvc.Application) { - // app.Register(...) - // app.Router.Use/UseGlobal/Done(...) - app.Handle(new(MyController)) - } - - type MyController struct {} - - func (m *MyController) BeforeActivation(b mvc.BeforeActivation) { - // b.Dependencies().Add/Remove - // b.Router().Use/UseGlobal/Done // and any standard API call you already know - - // 1-> Method - // 2-> Path - // 3-> The controller's function name to be parsed as handler - // 4-> Any handlers that should run before the MyCustomHandler - b.Handle("GET", "/something/{id:long}", "MyCustomHandler", anyMiddleware...) - } - - // GET: http://localhost:8080/root - func (m *MyController) Get() string { return "Hey" } - - // GET: http://localhost:8080/root/something/{id:long} - func (m *MyController) MyCustomHandler(id int64) string { return "MyCustomHandler says Hey" } - - -Persistence data inside your Controller struct (share data between requests) -by defining services to the Dependencies or have a `Singleton` controller scope. - -Share the dependencies between controllers or register them on a parent MVC Application, and ability -to modify dependencies per-controller on the `BeforeActivation` optional event callback inside a Controller, -i.e - - func(c *MyController) BeforeActivation(b mvc.BeforeActivation) { b.Dependencies().Add/Remove(...) } - -Access to the `Context` as a controller's field(no manual binding is neede) i.e `Ctx iris.Context` or via a method's input argument, -i.e - func(ctx iris.Context, otherArguments...) - -Models inside your Controller struct (set-ed at the Method function and rendered by the View). -You can return models from a controller's method or set a field in the request lifecycle -and return that field to another method, in the same request lifecycle. - -Flow as you used to, mvc application has its own `Router` which is a type of `iris/router.Party`, the standard iris api. -`Controllers` can be registered to any `Party`, including Subdomains, the Party's begin and done handlers work as expected. - -Optional `BeginRequest(ctx)` function to perform any initialization before the method execution, -useful to call middlewares or when many methods use the same collection of data. - -Optional `EndRequest(ctx)` function to perform any finalization after any method executed. - -Session dynamic dependency via manager's `Start` to the MVC Application, i.e - - mvcApp.Register(sessions.New(sessions.Config{Cookie: "iris_session_id"}).Start) - -Inheritance, recursively. - -Access to the dynamic path parameters via the controller's methods' input arguments, no binding is needed. -When you use the Iris' default syntax to parse handlers from a controller, you need to suffix the methods -with the `By` word, uppercase is a new sub path. Example: - -Register one or more relative paths and able to get path parameters, i.e - - If `mvc.New(app.Party("/user")).Handle(new(user.Controller))` - - - `func(*Controller) Get()` - `GET:/user` , as usual. - - `func(*Controller) Post()` - `POST:/user`, as usual. - - `func(*Controller) GetLogin()` - `GET:/user/login` - - `func(*Controller) PostLogin()` - `POST:/user/login` - - `func(*Controller) GetProfileFollowers()` - `GET:/user/profile/followers` - - `func(*Controller) PostProfileFollowers()` - `POST:/user/profile/followers` - - `func(*Controller) GetBy(id int64)` - `GET:/user/{param:long}` - - `func(*Controller) PostBy(id int64)` - `POST:/user/{param:long}` - - If `mvc.New(app.Party("/profile")).Handle(new(profile.Controller))` - - - `func(*Controller) GetBy(username string)` - `GET:/profile/{param:string}` - - If `mvc.New(app.Party("/assets")).Handle(new(file.Controller))` - - - `func(*Controller) GetByWildard(path string)` - `GET:/assets/{param:path}` - - If `mvc.New(app.Party("/equality")).Handle(new(profile.Equality))` - - - `func(*Controller) GetBy(is bool)` - `GET:/equality/{param:boolean}` - - `func(*Controller) GetByOtherBy(is bool, otherID int64)` - `GET:/equality/{paramfirst:boolean}/other/{paramsecond:long}` - - Supported types for method functions receivers: int, int64, bool and string. - -Response via output arguments, optionally, i.e - - func(c *ExampleController) Get() string | - (string, string) | - (string, int) | - (string, error) | - int | - (int, string) | - (any, int) | - error | - (int, error) | - (customStruct, error) | - (any, error) | - bool | - (any, bool) - customStruct | - (customStruct, int) | - (customStruct, string) | - `Result` or (`Result`, error) - -Where `any` means everything, from custom structs to standard language's types-. -`Result` is an interface which contains only that function: Dispatch(ctx iris.Context) -and Get where HTTP Method function(Post, Put, Delete...). - - -Iris MVC Method Result - -Iris has a very powerful and blazing fast MVC support, you can return any value of any type from a method function -and it will be sent to the client as expected. - -* if `string` then it's the body. -* if `string` is the second output argument then it's the content type. -* if `int` then it's the status code. -* if `bool` is false then it throws 404 not found http error by skipping everything else. -* if `error` and not nil then (any type) response will be omitted and error's text with a 400 bad request will be rendered instead. -* if `(int, error)` and error is not nil then the response result will be the error's text with the status code as `int`. -* if `custom struct` or `interface{}` or `slice` or `map` then it will be rendered as json, unless a `string` content type is following. -* if `mvc.Result` then it executes its `Dispatch` function, so good design patters can be used to split the model's logic where needed. - -Examples with good patterns to follow but not intend to be used in production of course can be found at: -https://github.com/kataras/iris/tree/master/_examples/#mvc. - - -Using Iris MVC for code reuse - -By creating components that are independent of one another, -developers are able to reuse components quickly and easily in other applications. -The same (or similar) view for one application can be refactored for another application with -different data because the view is simply handling how the data is being displayed to the user. - -If you're new to back-end web development read about the MVC architectural pattern first, -a good start is that wikipedia article: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller. - - - -That's the basics - -But you should have a basic idea of the framework by now, we just scratched the surface. -If you enjoy what you just saw and want to learn more, please follow the below links: + https://github.com/kataras/iris/wiki Examples: @@ -1808,9 +63,5 @@ Home Page: https://iris-go.com -Book (in-progress): - - https://docs.iris-go.com - */ package iris diff --git a/iris.go b/iris.go index 6cfb409b..0dc269e9 100644 --- a/iris.go +++ b/iris.go @@ -424,7 +424,7 @@ var ( // // If "cacheDur" <=0 then it returns the `NoCache` middleware instaed to disable the caching between browser's "back" and "forward" actions. // - // Usage: `app.Use(iris.StaticCache(24 * time.Hour))` or `app.Use(iris.Staticcache(-1))`. + // Usage: `app.Use(iris.StaticCache(24 * time.Hour))` or `app.Use(iris.StaticCache(-1))`. // A middleware, which is a simple Handler can be called inside another handler as well, example: // cacheMiddleware := iris.StaticCache(...) // func(ctx iris.Context){ @@ -449,7 +449,7 @@ var ( // Developers are free to extend this method's behavior // by watching system directories changes manually and use of the `ctx.WriteWithExpiration` // with a "modtime" based on the file modified date, - // simillary to the `HandleDir`(which sends status OK(200) and browser disk caching instead of 304). + // similar to the `HandleDir`(which sends status OK(200) and browser disk caching instead of 304). // // A shortcut of the `cache#Cache304`. Cache304 = cache.Cache304 @@ -501,6 +501,21 @@ var ( IsErrPath = context.IsErrPath ) +// Contains the enum values of the `Context.GetReferrer()` method, +// shortcuts of the context subpackage. +const ( + ReferrerInvalid = context.ReferrerInvalid + ReferrerIndirect = context.ReferrerIndirect + ReferrerDirect = context.ReferrerDirect + ReferrerEmail = context.ReferrerEmail + ReferrerSearch = context.ReferrerSearch + ReferrerSocial = context.ReferrerSocial + + ReferrerNotGoogleSearch = context.ReferrerNotGoogleSearch + ReferrerGoogleOrganicSearch = context.ReferrerGoogleOrganicSearch + ReferrerGoogleAdwords = context.ReferrerGoogleAdwords +) + // ConfigureHost accepts one or more `host#Configuration`, these configurators functions // can access the host created by `app.Run`, // they're being executed when application is ready to being served to the public.