mirror of
https://github.com/kataras/iris.git
synced 2025-03-14 11:06:27 +01:00
Publish version 11.1.0. Read HISTORY.md for details
Versioning API - https://github.com/kataras/iris/blob/master/HISTORY.md#su-18-november-2018--v1110 Former-commit-id: 59296266798a8fca3af65497ea63f8f84d60de79
This commit is contained in:
commit
a638e9ef81
6
Gopkg.lock
generated
6
Gopkg.lock
generated
|
@ -289,6 +289,12 @@
|
||||||
packages = ["internal","redis"]
|
packages = ["internal","redis"]
|
||||||
revision = "2cd21d9966bf7ff9ae091419744f0b3fb0fecace"
|
revision = "2cd21d9966bf7ff9ae091419744f0b3fb0fecace"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/hashicorp/go-version"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "b5a281d3160aa11950a6182bd9a9dc2cb1e02d50"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
|
|
|
@ -89,3 +89,7 @@
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/gomodule/redigo"
|
name = "github.com/gomodule/redigo"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/hashicorp/go-version"
|
||||||
|
version = "1.0.0"
|
151
HISTORY.md
151
HISTORY.md
|
@ -17,6 +17,155 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
|
||||||
|
|
||||||
**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 -u github.com/kataras/iris` or let the automatic updater do that for you.
|
||||||
|
|
||||||
|
# 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
|
# Fr, 09 November 2018 | v11.0.4
|
||||||
|
|
||||||
Add `Configuration.DisablePathCorrectionRedirection` - `iris.WithoutPathCorrectionRedirection` to support
|
Add `Configuration.DisablePathCorrectionRedirection` - `iris.WithoutPathCorrectionRedirection` to support
|
||||||
|
@ -119,7 +268,7 @@ For the craziest of us, click [here](https://github.com/kataras/iris/compare/v10
|
||||||
|
|
||||||
## Routing
|
## 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-writen and designed-first code we have for the high-level path syntax component called [macro interpreter](macro/interpreter).
|
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**.
|
The new router supports things like **closest wildcard resolution**.
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
**Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `go get -u github.com/kataras/iris` ή αφήστε το αυτόματο updater να το κάνει αυτό για σας.
|
**Πώς να αναβαθμίσετε**: Ανοίξτε την γραμμή εντολών σας και εκτελέστε αυτήν την εντολή: `go get -u github.com/kataras/iris` ή αφήστε το αυτόματο updater να το κάνει αυτό για σας.
|
||||||
|
|
||||||
|
# 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
|
# Fr, 09 November 2018 | v11.0.4
|
||||||
|
|
||||||
Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-09-november-2018--v1104) για να διαβάσετε στα αγγλικά τις αλλαγές που φέρνει το τελευταίο patch για την έκδοση 11.
|
Πατήστε [εδώ](https://github.com/kataras/iris/blob/master/HISTORY.md#fr-09-november-2018--v1104) για να διαβάσετε στα αγγλικά τις αλλαγές που φέρνει το τελευταίο patch για την έκδοση 11.
|
||||||
|
|
|
@ -17,6 +17,10 @@ Developers tidak diwajibkan untuk melakukan upgrade apabila mereka tidak membutu
|
||||||
|
|
||||||
**Cara Upgrade**: Bukan command-line anda dan eksekuis perintah ini: `go get -u github.com/kataras/iris` atau biarkan updater otomatis melakukannya untuk anda.
|
**Cara Upgrade**: Bukan command-line anda dan eksekuis perintah ini: `go get -u github.com/kataras/iris` atau biarkan updater otomatis melakukannya untuk anda.
|
||||||
|
|
||||||
|
# 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
|
# 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.
|
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.
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
**如何升级**: 打开命令行执行以下命令: `go get -u github.com/kataras/iris` 或者等待自动更新。
|
**如何升级**: 打开命令行执行以下命令: `go get -u github.com/kataras/iris` 或者等待自动更新。
|
||||||
|
|
||||||
|
# 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
|
# 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.
|
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.
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
# ⚡️ Update: community-driven version 11.1.0
|
||||||
|
|
||||||
|
Click [here](HISTORY.md#su-18-november-2018--v1110) to read about the versioning API that the most recent version of Iris brings to you.
|
||||||
|
|
||||||
# Iris Web Framework <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a> <a href="README_PT_BR.md"><img width="20px" src="https://iris-go.com/images/flag-pt-br.svg?v=10" /></a> <a href="README_JPN.md"><img width="20px" src="https://iris-go.com/images/flag-japan.svg?v=10" /></a>
|
# Iris Web Framework <a href="README_ZH.md"> <img width="20px" src="https://iris-go.com/images/flag-china.svg?v=10" /></a> <a href="README_RU.md"><img width="20px" src="https://iris-go.com/images/flag-russia.svg?v=10" /></a> <a href="README_ID.md"> <img width="20px" src="https://iris-go.com/images/flag-indonesia.svg?v=10" /></a> <a href="README_GR.md"><img width="20px" src="https://iris-go.com/images/flag-greece.svg?v=10" /></a> <a href="README_PT_BR.md"><img width="20px" src="https://iris-go.com/images/flag-pt-br.svg?v=10" /></a> <a href="README_JPN.md"><img width="20px" src="https://iris-go.com/images/flag-japan.svg?v=10" /></a>
|
||||||
|
|
||||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||||
|
|
||||||
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
||||||
|
|
||||||
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
Iris is a fast, simple yet fully featured and very efficient web framework for Go.
|
||||||
|
|
||||||
|
@ -1013,7 +1017,7 @@ Iris, unlike others, is 100% compatible with the standards and that's why the ma
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
- [HISTORY](HISTORY.md#fr-09-november-2018--v1104) file is your best friend, it contains information about the latest features and changes
|
- [HISTORY](HISTORY.md#su-18-november-2018--v1110) 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)
|
- 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)
|
- 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)
|
- 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)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||||
|
|
||||||
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
||||||
|
|
||||||
Το Iris είναι ένα γρήγορο, απλό αλλά και πλήρως λειτουργικό και πολύ αποδοτικό web framework για τη Go.
|
Το Iris είναι ένα γρήγορο, απλό αλλά και πλήρως λειτουργικό και πολύ αποδοτικό web framework για τη Go.
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ _Η τελευταία ενημέρωση έγινε την [Τρίτη, 21 Νο
|
||||||
|
|
||||||
## Υποστήριξη
|
## Υποστήριξη
|
||||||
|
|
||||||
- To [HISTORY](HISTORY_GR.md#fr-09-november-2018--v1104) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές
|
- To [HISTORY](HISTORY_GR.md#su-18-november-2018--v1110) αρχείο είναι ο καλύτερος σας φίλος, περιέχει πληροφορίες σχετικά με τις τελευταίες λειτουργίες(features) και αλλαγές
|
||||||
- Μήπως τυχαίνει να βρήκατε κάποιο bug; Δημοσιεύστε το στα [github issues](https://github.com/kataras/iris/issues)
|
- Μήπως τυχαίνει να βρήκατε κάποιο bug; Δημοσιεύστε το στα [github issues](https://github.com/kataras/iris/issues)
|
||||||
- Έχετε οποιεσδήποτε ερωτήσεις ή πρέπει να μιλήσετε με κάποιον έμπειρο για την επίλυση ενός προβλήματος σε πραγματικό χρόνο; Ελάτε μαζί μας στην [συνομιλία κοινότητας](https://chat.iris-go.com)
|
- Έχετε οποιεσδήποτε ερωτήσεις ή πρέπει να μιλήσετε με κάποιον έμπειρο για την επίλυση ενός προβλήματος σε πραγματικό χρόνο; Ελάτε μαζί μας στην [συνομιλία κοινότητας](https://chat.iris-go.com)
|
||||||
- Συμπληρώστε την αναφορά εμπειρίας χρήστη κάνοντας κλικ [εδώ](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- Συμπληρώστε την αναφορά εμπειρίας χρήστη κάνοντας κλικ [εδώ](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||||
|
|
||||||
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
||||||
|
|
||||||
Iris adalah web framework yang cepat, sederhana namun berfitur lengkap dan sangat efisien untuk Go.
|
Iris adalah web framework yang cepat, sederhana namun berfitur lengkap dan sangat efisien untuk Go.
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ _Diperbarui pada: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_
|
||||||
|
|
||||||
## Dukungan
|
## Dukungan
|
||||||
|
|
||||||
- File [HISTORY](HISTORY_ID.md#fr-09-november-2018--v1104) adalah sahabat anda, file tersebut memiliki informasi terkait fitur dan perubahan terbaru
|
- File [HISTORY](HISTORY_ID.md#su-18-november-2018--v1110) adalah sahabat anda, file tersebut memiliki informasi terkait fitur dan perubahan terbaru
|
||||||
- Apakah anda menemukan bug? Laporkan itu melalui [github issues](https://github.com/kataras/iris/issues)
|
- Apakah anda menemukan bug? Laporkan itu melalui [github issues](https://github.com/kataras/iris/issues)
|
||||||
- Apakah anda memiliki pertanyaan atau butuh untuk bicara kepada seseorang yang sudah berpengalaman untuk menyelesaikan masalah secara langsung? Gabung bersama kami di [community chat](https://chat.iris-go.com)
|
- Apakah anda memiliki pertanyaan atau butuh untuk bicara kepada seseorang yang sudah berpengalaman untuk menyelesaikan masalah secara langsung? Gabung bersama kami di [community chat](https://chat.iris-go.com)
|
||||||
- Lengkapi laporan user-experience berbasis formulir kami dengan tekan [disini](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- Lengkapi laporan user-experience berbasis formulir kami dengan tekan [disini](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||||
|
|
||||||
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
||||||
|
|
||||||
Irisはシンプルで高速、それにも関わらず充実した機能を有する効率的なGo言語のウェブフレームワークです。
|
Irisはシンプルで高速、それにも関わらず充実した機能を有する効率的なGo言語のウェブフレームワークです。
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ _Updated at: [Tuesday, 21 November 2017](_benchmarks/README_UNIX.md)_
|
||||||
|
|
||||||
## 支援
|
## 支援
|
||||||
|
|
||||||
- [HISTORY](HISTORY.md#fr-09-november-2018--v1104)ファイルはあなたの友人です。このファイルには、機能に関する最新の情報や変更点が記載されています。
|
- [HISTORY](HISTORY.md#su-18-november-2018--v1110)ファイルはあなたの友人です。このファイルには、機能に関する最新の情報や変更点が記載されています。
|
||||||
- バグを発見しましたか?[github issues](https://github.com/kataras/iris/issues)に投稿をお願い致します。
|
- バグを発見しましたか?[github issues](https://github.com/kataras/iris/issues)に投稿をお願い致します。
|
||||||
- 質問がありますか?または問題を即時に解決するため、熟練者に相談する必要がありますか?[community chat](https://chat.iris-go.com)に参加しましょう。
|
- 質問がありますか?または問題を即時に解決するため、熟練者に相談する必要がありますか?[community chat](https://chat.iris-go.com)に参加しましょう。
|
||||||
- [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)をクリックしてユーザーとしての体験を報告しましょう。
|
- [here](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)をクリックしてユーザーとしての体験を報告しましょう。
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||||
|
|
||||||
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
||||||
|
|
||||||
Iris é um framework rápido, simples porém completo e muito eficiente para a linguagem Go.
|
Iris é um framework rápido, simples porém completo e muito eficiente para a linguagem Go.
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ _Atualizado em : [Terça, 21 de Novembro de 2017](_benchmarks/README_UNIX.md)_
|
||||||
|
|
||||||
## Apoie
|
## Apoie
|
||||||
|
|
||||||
- [HISTORY](HISTORY.md#fr-09-november-2018--v1104) o arquivo HISTORY é o seu melhor amigo, ele contém informações sobre as últimas features e mudanças.
|
- [HISTORY](HISTORY.md#su-18-november-2018--v1110) o arquivo HISTORY é o seu melhor amigo, ele contém informações sobre as últimas features e mudanças.
|
||||||
- Econtrou algum bug ? Poste-o nas [issues](https://github.com/kataras/iris/issues)
|
- Econtrou algum bug ? Poste-o nas [issues](https://github.com/kataras/iris/issues)
|
||||||
- Possui alguma dúvida ou gostaria de falar com alguém experiente para resolver seu problema em tempo real ? Junte-se ao [chat da nossa comunidade](https://chat.iris-go.com).
|
- Possui alguma dúvida ou gostaria de falar com alguém experiente para resolver seu problema em tempo real ? Junte-se ao [chat da nossa comunidade](https://chat.iris-go.com).
|
||||||
- Complete nosso formulário de experiência do usuário clicando [aqui](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- Complete nosso formulário de experiência do usuário clicando [aqui](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||||
|
|
||||||
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
||||||
|
|
||||||
Iris - это быстрая, простая, но полнофункциональная и очень эффективная веб-платформа для Go.
|
Iris - это быстрая, простая, но полнофункциональная и очень эффективная веб-платформа для Go.
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ _Обновлено: [Вторник, 21 ноября 2017 г.](_benchmarks/READ
|
||||||
|
|
||||||
## Поддержка
|
## Поддержка
|
||||||
|
|
||||||
- Файл [HISTORY](HISTORY.md#fr-09-november-2018--v1104) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях
|
- Файл [HISTORY](HISTORY.md#su-18-november-2018--v1110) - ваш лучший друг, он содержит информацию о последних особенностях и всех изменениях
|
||||||
- Вы случайно обнаружили ошибку? Опубликуйте ее на [Github вопросы](https://github.com/kataras/iris/issues)
|
- Вы случайно обнаружили ошибку? Опубликуйте ее на [Github вопросы](https://github.com/kataras/iris/issues)
|
||||||
- У Вас есть какие-либо вопросы или Вам нужно поговорить с кем-то, кто бы смог решить Вашу проблему в режиме реального времени? Присоединяйтесь к нам в [чате сообщества](https://chat.iris-go.com)
|
- У Вас есть какие-либо вопросы или Вам нужно поговорить с кем-то, кто бы смог решить Вашу проблему в режиме реального времени? Присоединяйтесь к нам в [чате сообщества](https://chat.iris-go.com)
|
||||||
- Заполните наш отчет о пользовательском опыте на основе формы, нажав [здесь](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- Заполните наш отчет о пользовательском опыте на основе формы, нажав [здесь](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
<a href="https://iris-go.com"> <img align="right" width="169px" src="https://iris-go.com/images/icon.svg?v=a" title="logo created by @merry.dii" /> </a>
|
||||||
|
|
||||||
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
[](https://travis-ci.org/kataras/iris)<!-- [](https://github.com/kataras/iris/releases)--> [](http://goreportcard.com/report/kataras/iris) [](https://marketplace.visualstudio.com/items?itemName=kataras2006.iris)<!--[](https://github.com/kataras/iris/issues?q=is%3Aissue+is%3Aclosed)--> [](https://kataras.rocket.chat/channel/iris) [](https://github.com/kataras/iris/tree/master/_examples/routing) [](https://github.com/kataras/iris/releases)
|
||||||
|
|
||||||
Iris 是一款超快、简洁高效的 Go 语言 Web开发框架。
|
Iris 是一款超快、简洁高效的 Go 语言 Web开发框架。
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ _更新于: [2017年11月21日星期二](_benchmarks/README_UNIX.md)_
|
||||||
|
|
||||||
## 支持
|
## 支持
|
||||||
|
|
||||||
- [更新记录](HISTORY_ZH.md#fr-09-november-2018--v1104) 是您最好的朋友,它包含有关最新功能和更改的信息
|
- [更新记录](HISTORY_ZH.md#su-18-november-2018--v1110) 是您最好的朋友,它包含有关最新功能和更改的信息
|
||||||
- 你碰巧找到了一个错误? 请提交 [github issues](https://github.com/kataras/iris/issues)
|
- 你碰巧找到了一个错误? 请提交 [github issues](https://github.com/kataras/iris/issues)
|
||||||
- 您是否有任何疑问或需要与有经验的人士交谈以实时解决问题? [加入我们的聊天](https://chat.iris-go.com)
|
- 您是否有任何疑问或需要与有经验的人士交谈以实时解决问题? [加入我们的聊天](https://chat.iris-go.com)
|
||||||
- [点击这里完成我们基于表单的用户体验报告](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
- [点击这里完成我们基于表单的用户体验报告](https://docs.google.com/forms/d/e/1FAIpQLSdCxZXPANg_xHWil4kVAdhmh7EBBHQZ_4_xSZVDL-oCC_z5pA/viewform?usp=sf_link)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
11.0.4:https://github.com/kataras/iris/blob/master/HISTORY.md#fr-09-november-2018--v1104
|
11.1.0:https://github.com/kataras/iris/blob/master/HISTORY.md#su-18-november-2018--v1110
|
|
@ -158,6 +158,11 @@ Navigate through examples for a better understanding.
|
||||||
* [per-route](routing/writing-a-middleware/per-route/main.go)
|
* [per-route](routing/writing-a-middleware/per-route/main.go)
|
||||||
* [globally](routing/writing-a-middleware/globally/main.go)
|
* [globally](routing/writing-a-middleware/globally/main.go)
|
||||||
|
|
||||||
|
### Versioning
|
||||||
|
|
||||||
|
- [How it works](https://github.com/kataras/iris/blob/master/versioning/README.md)
|
||||||
|
- [Example](versioning/main.go)
|
||||||
|
|
||||||
### hero
|
### hero
|
||||||
|
|
||||||
- [Basic](hero/basic/main.go)
|
- [Basic](hero/basic/main.go)
|
||||||
|
|
|
@ -28,30 +28,65 @@ func main() {
|
||||||
// otherwise it pre-compiles the regexp and adds the necessary middleware(s).
|
// otherwise it pre-compiles the regexp and adds the necessary middleware(s).
|
||||||
//
|
//
|
||||||
// Standard macro types for parameters:
|
// Standard macro types for parameters:
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// | {param:string} |
|
// | {param:string} |
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// string type
|
// string type
|
||||||
// anything
|
// anything (single path segmnent)
|
||||||
//
|
//
|
||||||
// +-------------------------------+
|
// +-------------------------------+
|
||||||
// | {param:int} or {param:int} |
|
// | {param:int} |
|
||||||
// +-------------------------------+
|
// +-------------------------------+
|
||||||
// int type
|
// int type
|
||||||
// both positive and negative numbers, any number of digits (ctx.Params().GetInt will limit the digits based on the host arch)
|
// -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch
|
||||||
//
|
//
|
||||||
// +-------------------------------+
|
// +------------------------+
|
||||||
// | {param:int64} or {param:long} |
|
// | {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
|
// int64 type
|
||||||
// -9223372036854775808 to 9223372036854775807
|
// -9223372036854775808 to 9223372036854775807
|
||||||
//
|
//
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
|
// | {param:uint} |
|
||||||
|
// +------------------------+
|
||||||
|
// uint type
|
||||||
|
// 0 to 18446744073709551615 (x64) or 0 to 4294967295 (x32)
|
||||||
|
//
|
||||||
|
// +------------------------+
|
||||||
// | {param:uint8} |
|
// | {param:uint8} |
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// uint8 type
|
// uint8 type
|
||||||
// 0 to 255
|
// 0 to 255
|
||||||
//
|
//
|
||||||
|
// +------------------------+
|
||||||
|
// | {param:uint16} |
|
||||||
|
// +------------------------+
|
||||||
|
// uint16 type
|
||||||
|
// 0 to 65535
|
||||||
|
//
|
||||||
|
// +------------------------+
|
||||||
|
// | {param:uint32} |
|
||||||
|
// +------------------------+
|
||||||
|
// uint32 type
|
||||||
|
// 0 to 4294967295
|
||||||
//
|
//
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// | {param:uint64} |
|
// | {param:uint64} |
|
||||||
|
@ -66,15 +101,15 @@ func main() {
|
||||||
// only "1" or "t" or "T" or "TRUE" or "true" or "True"
|
// only "1" or "t" or "T" or "TRUE" or "true" or "True"
|
||||||
// or "0" or "f" or "F" or "FALSE" or "false" or "False"
|
// or "0" or "f" or "F" or "FALSE" or "false" or "False"
|
||||||
//
|
//
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// | {param:alphabetical} |
|
// | {param:alphabetical} |
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// alphabetical/letter type
|
// alphabetical/letter type
|
||||||
// letters only (upper or lowercase)
|
// letters only (upper or lowercase)
|
||||||
//
|
//
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// | {param:file} |
|
// | {param:file} |
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// file type
|
// file type
|
||||||
// letters (upper or lowercase)
|
// letters (upper or lowercase)
|
||||||
// numbers (0-9)
|
// numbers (0-9)
|
||||||
|
@ -83,12 +118,12 @@ func main() {
|
||||||
// point (.)
|
// point (.)
|
||||||
// no spaces ! or other character
|
// no spaces ! or other character
|
||||||
//
|
//
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// | {param:path} |
|
// | {param:path} |
|
||||||
// +------------------------+
|
// +------------------------+
|
||||||
// path type
|
// path type
|
||||||
// anything, should be the last part, more than one path segment,
|
// anything, should be the last part, can be more than one path segment,
|
||||||
// i.e: /path1/path2/path3 , ctx.Params().Get("param") == "/path1/path2/path3"
|
// 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
|
// if type is missing then parameter's type is defaulted to string, so
|
||||||
// {param} == {param:string}.
|
// {param} == {param:string}.
|
||||||
|
|
1
_examples/versioning/README.md
Normal file
1
_examples/versioning/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Head over to the [kataras/iris/versioning/README.md](https://github.com/kataras/iris/blob/master/versioning/README.md) instead.
|
73
_examples/versioning/main.go
Normal file
73
_examples/versioning/main.go
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/versioning"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
examplePerRoute(app)
|
||||||
|
examplePerParty(app)
|
||||||
|
|
||||||
|
// Read the README.md before any action.
|
||||||
|
app.Run(iris.Addr(":8080"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// How to test:
|
||||||
|
// Open Postman
|
||||||
|
// GET: localhost:8080/api/cats
|
||||||
|
// Headers[1] = Accept-Version: "1" and repeat with
|
||||||
|
// Headers[1] = Accept-Version: "2.5"
|
||||||
|
// or even "Accept": "application/json; version=2.5"
|
||||||
|
func examplePerRoute(app *iris.Application) {
|
||||||
|
app.Get("/api/cats", versioning.NewMatcher(versioning.Map{
|
||||||
|
"1": catsVersionExactly1Handler,
|
||||||
|
">= 2, < 3": catsV2Handler,
|
||||||
|
versioning.NotFound: versioning.NotFoundHandler,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// How to test:
|
||||||
|
// Open Postman
|
||||||
|
// GET: localhost:8080/api/users
|
||||||
|
// Headers[1] = Accept-Version: "1.9.9" and repeat with
|
||||||
|
// Headers[1] = Accept-Version: "2.5"
|
||||||
|
//
|
||||||
|
// POST: localhost:8080/api/users/new
|
||||||
|
// Headers[1] = Accept-Version: "1.8.3"
|
||||||
|
//
|
||||||
|
// POST: localhost:8080/api/users
|
||||||
|
// Headers[1] = Accept-Version: "2"
|
||||||
|
func examplePerParty(app *iris.Application) {
|
||||||
|
usersAPI := app.Party("/api/users")
|
||||||
|
|
||||||
|
// version 1.
|
||||||
|
usersAPIV1 := versioning.NewGroup(">= 1, < 2")
|
||||||
|
usersAPIV1.Get("/", func(ctx iris.Context) {
|
||||||
|
ctx.Writef("v1 resource: /api/users handler")
|
||||||
|
})
|
||||||
|
usersAPIV1.Post("/new", func(ctx iris.Context) {
|
||||||
|
ctx.Writef("v1 resource: /api/users/new post handler")
|
||||||
|
})
|
||||||
|
|
||||||
|
// version 2.
|
||||||
|
usersAPIV2 := versioning.NewGroup(">= 2, < 3")
|
||||||
|
usersAPIV2.Get("/", func(ctx iris.Context) {
|
||||||
|
ctx.Writef("v2 resource: /api/users handler")
|
||||||
|
})
|
||||||
|
usersAPIV2.Post("/", func(ctx iris.Context) {
|
||||||
|
ctx.Writef("v2 resource: /api/users post handler")
|
||||||
|
})
|
||||||
|
|
||||||
|
versioning.RegisterGroups(usersAPI, versioning.NotFoundHandler, usersAPIV1, usersAPIV2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func catsVersionExactly1Handler(ctx iris.Context) {
|
||||||
|
ctx.Writef("v1 exactly resource: /api/cats handler")
|
||||||
|
}
|
||||||
|
|
||||||
|
func catsV2Handler(ctx iris.Context) {
|
||||||
|
ctx.Writef("v2 resource: /api/cats handler")
|
||||||
|
}
|
4
doc.go
4
doc.go
|
@ -35,7 +35,7 @@ Source code and other details for the project are available at GitHub:
|
||||||
|
|
||||||
Current Version
|
Current Version
|
||||||
|
|
||||||
11.0.4
|
11.1.0
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
|
|
||||||
|
@ -800,7 +800,7 @@ Standard macro types for parameters:
|
||||||
+------------------------+
|
+------------------------+
|
||||||
path type
|
path type
|
||||||
anything, should be the last part, can be more than one path segment,
|
anything, should be the last part, can be more than one path segment,
|
||||||
i.e: "/test/*param" and request: "/test/path1/path2/path3" , ctx.Params().Get("param") == "path1/path2/path3"
|
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
|
if type is missing then parameter's type is defaulted to string, so
|
||||||
{param} == {param:string}.
|
{param} == {param:string}.
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -20,6 +20,7 @@ require (
|
||||||
github.com/google/go-querystring v1.0.0 // indirect
|
github.com/google/go-querystring v1.0.0 // indirect
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c // indirect
|
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c // indirect
|
||||||
github.com/gorilla/websocket v1.4.0
|
github.com/gorilla/websocket v1.4.0
|
||||||
|
github.com/hashicorp/go-version v1.0.0
|
||||||
github.com/imkira/go-interpol v1.1.0 // indirect
|
github.com/imkira/go-interpol v1.1.0 // indirect
|
||||||
github.com/iris-contrib/blackfriday v2.0.0+incompatible
|
github.com/iris-contrib/blackfriday v2.0.0+incompatible
|
||||||
github.com/iris-contrib/formBinder v0.0.0-20171010160137-ad9fb86c356f
|
github.com/iris-contrib/formBinder v0.0.0-20171010160137-ad9fb86c356f
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -42,6 +42,8 @@ github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSf
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8=
|
||||||
|
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
|
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
|
||||||
|
|
2
iris.go
2
iris.go
|
@ -33,7 +33,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Version is the current version number of the Iris Web Framework.
|
// Version is the current version number of the Iris Web Framework.
|
||||||
Version = "11.0.4"
|
Version = "11.1.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTP status codes as registered with IANA.
|
// HTTP status codes as registered with IANA.
|
||||||
|
|
1
versioning/AUTHORS
Normal file
1
versioning/AUTHORS
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Gerasimos Maropoulos <kataras2006@hotmail.com>
|
27
versioning/LICENSE
Normal file
27
versioning/LICENSE
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2018 Gerasimos Maropoulos. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Iris nor the names of its
|
||||||
|
contributor, Gerasimos Maropoulos, may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
142
versioning/README.md
Normal file
142
versioning/README.md
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
# Versioning
|
||||||
|
|
||||||
|
The [versioning](https://github.com/kataras/iris/tree/master/versioning) package provides [semver](https://semver.org/) versioning for your APIs. It implements all the suggestions written at [api-guidelines](https://github.com/byrondover/api-guidelines/blob/master/Guidelines.md#versioning) and more.
|
||||||
|
|
||||||
|
|
||||||
|
The version comparison is done by the [go-version](https://github.com/hashicorp/go-version) package. It supports matching over patterns like `">= 1.0, < 3"` and etc.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- per route version matching, a normal iris handler with "switch" cases via Map for version => handler
|
||||||
|
- per group versioned routes and deprecation API
|
||||||
|
- version matching like ">= 1.0, < 2.0" or just "2.0.1" and etc.
|
||||||
|
- version not found handler (can be customized by simply adding the versioning.NotFound: customNotMatchVersionHandler on the Map)
|
||||||
|
- version is retrieved from the "Accept" and "Accept-Version" headers (can be customized via middleware)
|
||||||
|
- respond with "X-API-Version" header, if version found.
|
||||||
|
- deprecation options with customizable "X-API-Warn", "X-API-Deprecation-Date", "X-API-Deprecation-Info" headers via `Deprecated` wrapper.
|
||||||
|
|
||||||
|
## Get version
|
||||||
|
|
||||||
|
Current request version is retrieved by `versioning.GetVersion(ctx)`.
|
||||||
|
|
||||||
|
By default the `GetVersion` will try to read from:
|
||||||
|
- `Accept` header, i.e `Accept: "application/json; version=1.0"`
|
||||||
|
- `Accept-Version` header, i.e `Accept-Version: "1.0"`
|
||||||
|
|
||||||
|
You can also set a custom version for a handler via a middleware by using the context's store values.
|
||||||
|
For example:
|
||||||
|
```go
|
||||||
|
func(ctx iris.Context) {
|
||||||
|
ctx.Values().Set(versioning.Key, ctx.URLParamDefault("version", "1.0"))
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Match version to handler
|
||||||
|
|
||||||
|
The `versioning.NewMatcher(versioning.Map) iris.Handler` creates a single handler which decides what handler need to be executed based on the requested version.
|
||||||
|
|
||||||
|
```go
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
// middleware for all versions.
|
||||||
|
myMiddleware := func(ctx iris.Context) {
|
||||||
|
// [...]
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
myCustomNotVersionFound := func(ctx iris.Context) {
|
||||||
|
ctx.StatusCode(404)
|
||||||
|
ctx.Writef("%s version not found", versioning.GetVersion(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
userAPI := app.Party("/api/user")
|
||||||
|
userAPI.Get("/", myMiddleware, versioning.NewMatcher(versioning.Map{
|
||||||
|
"1.0": sendHandler(v10Response),
|
||||||
|
">= 2, < 3": sendHandler(v2Response),
|
||||||
|
versioning.NotFound: myCustomNotVersionFound,
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deprecation
|
||||||
|
|
||||||
|
Using the `versioning.Deprecated(handler iris.Handler, options versioning.DeprecationOptions) iris.Handler` function you can mark a specific handler version as deprecated.
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
v10Handler := versioning.Deprecated(sendHandler(v10Response), versioning.DeprecationOptions{
|
||||||
|
// if empty defaults to: "WARNING! You are using a deprecated version of this API."
|
||||||
|
WarnMessage string
|
||||||
|
DeprecationDate time.Time
|
||||||
|
DeprecationInfo string
|
||||||
|
})
|
||||||
|
|
||||||
|
userAPI.Get("/", versioning.NewMatcher(versioning.Map{
|
||||||
|
"1.0": v10Handler,
|
||||||
|
// [...]
|
||||||
|
}))
|
||||||
|
```
|
||||||
|
|
||||||
|
This will make the handler to send these headers to the client:
|
||||||
|
|
||||||
|
- `"X-API-Warn": options.WarnMessage`
|
||||||
|
- `"X-API-Deprecation-Date": context.FormatTime(ctx, options.DeprecationDate))`
|
||||||
|
- `"X-API-Deprecation-Info": options.DeprecationInfo`
|
||||||
|
|
||||||
|
> versioning.DefaultDeprecationOptions can be passed instead if you don't care about Date and Info.
|
||||||
|
|
||||||
|
## Grouping routes by version
|
||||||
|
|
||||||
|
Grouping routes by version is possible as well.
|
||||||
|
|
||||||
|
Using the `versioning.NewGroup(version string) *versioning.Group` function you can create a group to register your versioned routes.
|
||||||
|
The `versioning.RegisterGroups(r iris.Party, versionNotFoundHandler iris.Handler, groups ...*versioning.Group)` must be called in the end in order to register the routes to a specific `Party`.
|
||||||
|
|
||||||
|
```go
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
userAPI := app.Party("/api/user")
|
||||||
|
// [... static serving, middlewares and etc goes here].
|
||||||
|
|
||||||
|
userAPIV10 := versioning.NewGroup("1.0")
|
||||||
|
userAPIV10.Get("/", sendHandler(v10Response))
|
||||||
|
|
||||||
|
userAPIV2 := versioning.NewGroup(">= 2, < 3")
|
||||||
|
userAPIV2.Get("/", sendHandler(v2Response))
|
||||||
|
userAPIV2.Post("/", sendHandler(v2Response))
|
||||||
|
userAPIV2.Put("/other", sendHandler(v2Response))
|
||||||
|
|
||||||
|
versioning.RegisterGroups(userAPI, versioning.NotFoundHandler, userAPIV10, userAPIV2)
|
||||||
|
```
|
||||||
|
|
||||||
|
> A middleware can be registered to the actual `iris.Party` only, using the methods we learnt above, i.e by using the `versioning.Match` in order to detect what code/handler you want to be executed when "x" or no version is requested.
|
||||||
|
|
||||||
|
### Deprecation for Group
|
||||||
|
|
||||||
|
Just call the `Deprecated(versioning.DeprecationOptions)` on the group you want to notify your API consumers that this specific version is deprecated.
|
||||||
|
|
||||||
|
```go
|
||||||
|
userAPIV10 := versioning.NewGroup("1.0").Deprecated(versioning.DefaultDeprecationOptions)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compare version manually from inside your handlers
|
||||||
|
|
||||||
|
```go
|
||||||
|
// reports if the "version" is matching to the "is".
|
||||||
|
// the "is" can be a constraint like ">= 1, < 3".
|
||||||
|
If(version string, is string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
// same as `If` but expects a Context to read the requested version.
|
||||||
|
Match(ctx iris.Context, expectedVersion string) bool
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
app.Get("/api/user", func(ctx iris.Context) {
|
||||||
|
if versioning.Match(ctx, ">= 2.2.3") {
|
||||||
|
// [logic for >= 2.2.3 version of your handler goes here]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
50
versioning/deprecation.go
Normal file
50
versioning/deprecation.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package versioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeprecationOptions describes the deprecation headers key-values.
|
||||||
|
// - "X-API-Warn": options.WarnMessage
|
||||||
|
// - "X-API-Deprecation-Date": context.FormatTime(ctx, options.DeprecationDate))
|
||||||
|
// - "X-API-Deprecation-Info": options.DeprecationInfo
|
||||||
|
type DeprecationOptions struct {
|
||||||
|
WarnMessage string
|
||||||
|
DeprecationDate time.Time
|
||||||
|
DeprecationInfo string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldHandle reports whether the deprecation headers should be present or no.
|
||||||
|
func (opts DeprecationOptions) ShouldHandle() bool {
|
||||||
|
return opts.WarnMessage != "" || !opts.DeprecationDate.IsZero() || opts.DeprecationInfo != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultDeprecationOptions are the default deprecation options,
|
||||||
|
// it defaults the "X-API-Warn" header to a generic message.
|
||||||
|
var DefaultDeprecationOptions = DeprecationOptions{
|
||||||
|
WarnMessage: "WARNING! You are using a deprecated version of this API.",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated marks a specific handler as a deprecated.
|
||||||
|
// Deprecated can be used to tell the clients that
|
||||||
|
// a newer version of that specific resource is available instead.
|
||||||
|
func Deprecated(handler context.Handler, options DeprecationOptions) context.Handler {
|
||||||
|
if options.WarnMessage == "" {
|
||||||
|
options.WarnMessage = DefaultDeprecationOptions.WarnMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(ctx context.Context) {
|
||||||
|
handler(ctx)
|
||||||
|
ctx.Header("X-API-Warn", options.WarnMessage)
|
||||||
|
|
||||||
|
if !options.DeprecationDate.IsZero() {
|
||||||
|
ctx.Header("X-API-Deprecation-Date", context.FormatTime(ctx, options.DeprecationDate))
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.DeprecationInfo != "" {
|
||||||
|
ctx.Header("X-API-Deprecation-Info", options.DeprecationInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
versioning/deprecation_test.go
Normal file
33
versioning/deprecation_test.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package versioning_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/httptest"
|
||||||
|
"github.com/kataras/iris/versioning"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeprecated(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
writeVesion := func(ctx iris.Context) {
|
||||||
|
ctx.WriteString(versioning.GetVersion(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := versioning.DeprecationOptions{
|
||||||
|
WarnMessage: "deprecated, see <this link>",
|
||||||
|
DeprecationDate: time.Now().UTC(),
|
||||||
|
DeprecationInfo: "a bigger version is available, see <this link> for more information",
|
||||||
|
}
|
||||||
|
app.Get("/", versioning.Deprecated(writeVesion, opts))
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
|
||||||
|
ex := e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect()
|
||||||
|
ex.Status(iris.StatusOK).Body().Equal("1.0")
|
||||||
|
ex.Header("X-API-Warn").Equal(opts.WarnMessage)
|
||||||
|
expectedDateStr := opts.DeprecationDate.Format(app.ConfigurationReadOnly().GetTimeFormat())
|
||||||
|
ex.Header("X-API-Deprecation-Date").Equal(expectedDateStr)
|
||||||
|
}
|
185
versioning/group.go
Normal file
185
versioning/group.go
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
package versioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/context"
|
||||||
|
"github.com/kataras/iris/core/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
vroute struct {
|
||||||
|
method string
|
||||||
|
path string
|
||||||
|
versions Map
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group is a group of version-based routes.
|
||||||
|
// One version per one or more routes.
|
||||||
|
Group struct {
|
||||||
|
version string
|
||||||
|
extraMethods []string
|
||||||
|
routes []vroute
|
||||||
|
|
||||||
|
deprecation DeprecationOptions
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewGroup returns a ptr to Group based on the given "version".
|
||||||
|
//
|
||||||
|
// See `Handle` and `RegisterGroups` for more.
|
||||||
|
func NewGroup(version string) *Group {
|
||||||
|
return &Group{
|
||||||
|
version: version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated marks this group and all its versioned routes
|
||||||
|
// as deprecated versions of that endpoint.
|
||||||
|
// It can be called in the end just before `RegisterGroups`
|
||||||
|
// or first by `NewGroup(...).Deprecated(...)`. It returns itself.
|
||||||
|
func (g *Group) Deprecated(options DeprecationOptions) *Group {
|
||||||
|
// if `Deprecated` is called in the end.
|
||||||
|
for _, r := range g.routes {
|
||||||
|
r.versions[g.version] = Deprecated(r.versions[g.version], options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the options if called before registering any versioned routes.
|
||||||
|
g.deprecation = options
|
||||||
|
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowMethods can be called before `Handle/Get/Post...`
|
||||||
|
// to tell the underline router that all routes should be registered
|
||||||
|
// to these "methods" as well.
|
||||||
|
func (g *Group) AllowMethods(methods ...string) *Group {
|
||||||
|
g.extraMethods = append(g.extraMethods, methods...)
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) addVRoute(method, path string, handler context.Handler) {
|
||||||
|
for _, r := range g.routes { // check if route already exists.
|
||||||
|
if r.method == method && r.path == path {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.routes = append(g.routes, vroute{
|
||||||
|
method: method,
|
||||||
|
path: path,
|
||||||
|
versions: Map{g.version: handler},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle registers a versioned route to the group.
|
||||||
|
// A call of `RegisterGroups` is necessary in order to register the actual routes
|
||||||
|
// when the group is complete.
|
||||||
|
//
|
||||||
|
// `RegisterGroups` for more.
|
||||||
|
func (g *Group) Handle(method string, path string, handler context.Handler) {
|
||||||
|
if g.deprecation.ShouldHandle() { // if `Deprecated` called first.
|
||||||
|
handler = Deprecated(handler, g.deprecation)
|
||||||
|
}
|
||||||
|
|
||||||
|
methods := append(g.extraMethods, method)
|
||||||
|
|
||||||
|
for _, method := range methods {
|
||||||
|
g.addVRoute(method, path, handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// None registers an "offline" versioned route
|
||||||
|
// see `context#ExecRoute(routeName)` and routing examples.
|
||||||
|
func (g *Group) None(path string, handler context.Handler) {
|
||||||
|
g.Handle(router.MethodNone, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get registers a versioned route for the Get http method.
|
||||||
|
func (g *Group) Get(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodGet, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post registers a versioned route for the Post http method.
|
||||||
|
func (g *Group) Post(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodPost, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put registers a versioned route for the Put http method
|
||||||
|
func (g *Group) Put(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodPut, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete registers a versioned route for the Delete http method.
|
||||||
|
func (g *Group) Delete(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodDelete, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect registers a versioned route for the Connect http method.
|
||||||
|
func (g *Group) Connect(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodConnect, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head registers a versioned route for the Head http method.
|
||||||
|
func (g *Group) Head(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodHead, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options registers a versioned route for the Options http method.
|
||||||
|
func (g *Group) Options(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodOptions, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch registers a versioned route for the Patch http method.
|
||||||
|
func (g *Group) Patch(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodPatch, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace registers a versioned route for the Trace http method.
|
||||||
|
func (g *Group) Trace(path string, handler context.Handler) {
|
||||||
|
g.Handle(http.MethodTrace, path, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any registers a versioned route for ALL of the http methods
|
||||||
|
// (Get,Post,Put,Head,Patch,Options,Connect,Delete).
|
||||||
|
func (g *Group) Any(registeredPath string, handler context.Handler) {
|
||||||
|
g.Get(registeredPath, handler)
|
||||||
|
g.Post(registeredPath, handler)
|
||||||
|
g.Put(registeredPath, handler)
|
||||||
|
g.Delete(registeredPath, handler)
|
||||||
|
g.Connect(registeredPath, handler)
|
||||||
|
g.Head(registeredPath, handler)
|
||||||
|
g.Options(registeredPath, handler)
|
||||||
|
g.Patch(registeredPath, handler)
|
||||||
|
g.Trace(registeredPath, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterGroups registers one or more groups to an `iris.Party` or to the root router.
|
||||||
|
// See `NewGroup` and `NotFoundHandler` too.
|
||||||
|
func RegisterGroups(r router.Party, notFoundHandler context.Handler, groups ...*Group) (actualRoutes []*router.Route) {
|
||||||
|
var total []vroute
|
||||||
|
for _, g := range groups {
|
||||||
|
inner:
|
||||||
|
for _, r := range g.routes {
|
||||||
|
for i, tr := range total {
|
||||||
|
if tr.method == r.method && tr.path == r.path {
|
||||||
|
total[i].versions[g.version] = r.versions[g.version]
|
||||||
|
continue inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total = append(total, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vr := range total {
|
||||||
|
if notFoundHandler != nil {
|
||||||
|
vr.versions[NotFound] = notFoundHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
route := r.Handle(vr.method, vr.path, NewMatcher(vr.versions))
|
||||||
|
actualRoutes = append(actualRoutes, route)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
95
versioning/version.go
Normal file
95
versioning/version.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package versioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kataras/iris/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AcceptVersionHeaderKey is the header key of "Accept-Version".
|
||||||
|
AcceptVersionHeaderKey = "Accept-Version"
|
||||||
|
// AcceptHeaderKey is the header key of "Accept".
|
||||||
|
AcceptHeaderKey = "Accept"
|
||||||
|
// AcceptHeaderVersionValue is the Accept's header value search term the requested version.
|
||||||
|
AcceptHeaderVersionValue = "version"
|
||||||
|
|
||||||
|
// Key is the context key of the version, can be used to manually modify the "requested" version.
|
||||||
|
// Example of how you can change the default behavior to extract a requested version (which is by headers)
|
||||||
|
// from a "version" url parameter instead:
|
||||||
|
// func(ctx iris.Context) { // &version=1
|
||||||
|
// ctx.Values().Set(versioning.Key, ctx.URLParamDefault("version", "1"))
|
||||||
|
// ctx.Next()
|
||||||
|
// }
|
||||||
|
Key = "iris.api.version" // for use inside the ctx.Values(), not visible by the user.
|
||||||
|
// NotFound is the key that can be used inside a `Map` or inside `ctx.Values().Set(versioning.Key, versioning.NotFound)`
|
||||||
|
// to tell that a version wasn't found, therefore the not found handler should handle the request instead.
|
||||||
|
NotFound = Key + ".notfound"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NotFoundHandler is the default version not found handler that
|
||||||
|
// is executed from `NewMatcher` when no version is registered as available to dispatch a resource.
|
||||||
|
var NotFoundHandler = func(ctx context.Context) {
|
||||||
|
// 303 is an option too,
|
||||||
|
// end-dev has the chance to change that behavior by using the NotFound in the map:
|
||||||
|
//
|
||||||
|
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||||
|
/*
|
||||||
|
10.5.2 501 Not Implemented
|
||||||
|
|
||||||
|
The server does not support the functionality required to fulfill the request.
|
||||||
|
This is the appropriate response when the server does not
|
||||||
|
recognize the request method and is not capable of supporting it for any resource.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ctx.StatusCode(501)
|
||||||
|
ctx.WriteString("version not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersion returns the current request version.
|
||||||
|
//
|
||||||
|
// 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"
|
||||||
|
//
|
||||||
|
// However, the end developer can also set a custom version for a handler via a middleware by using the context's store key
|
||||||
|
// for versions (see `Key` for further details on that).
|
||||||
|
func GetVersion(ctx context.Context) string {
|
||||||
|
// firstly by context store, if manually set-ed by a middleware.
|
||||||
|
if version := ctx.Values().GetString(Key); version != "" {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
|
// secondly by the "Accept-Version" header.
|
||||||
|
if version := ctx.GetHeader(AcceptVersionHeaderKey); version != "" {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
|
// thirdly by the "Accept" header which is like"...; version=1.0"
|
||||||
|
acceptValue := ctx.GetHeader(AcceptHeaderKey)
|
||||||
|
if acceptValue != "" {
|
||||||
|
if idx := strings.Index(acceptValue, AcceptHeaderVersionValue); idx != -1 {
|
||||||
|
rem := acceptValue[idx:]
|
||||||
|
startVersion := strings.Index(rem, "=")
|
||||||
|
if startVersion == -1 || len(rem) < startVersion+1 {
|
||||||
|
return NotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
rem = rem[startVersion+1:]
|
||||||
|
|
||||||
|
end := strings.Index(rem, " ")
|
||||||
|
if end == -1 {
|
||||||
|
end = strings.Index(rem, ";")
|
||||||
|
}
|
||||||
|
if end == -1 {
|
||||||
|
end = len(rem)
|
||||||
|
}
|
||||||
|
|
||||||
|
if version := rem[:end]; version != "" {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound
|
||||||
|
}
|
48
versioning/version_test.go
Normal file
48
versioning/version_test.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package versioning_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/httptest"
|
||||||
|
"github.com/kataras/iris/versioning"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetVersion(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
writeVesion := func(ctx iris.Context) {
|
||||||
|
ctx.WriteString(versioning.GetVersion(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Get("/", writeVesion)
|
||||||
|
app.Get("/manual", func(ctx iris.Context) {
|
||||||
|
ctx.Values().Set(versioning.Key, "11.0.5")
|
||||||
|
ctx.Next()
|
||||||
|
}, writeVesion)
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal("1.0")
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=2.1").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal("2.1")
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=2.1 ;other=dsa").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal("2.1")
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=2.1").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal("2.1")
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=1").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal("1")
|
||||||
|
|
||||||
|
// unknown versions.
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(versioning.NotFound)
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(versioning.NotFound)
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version= ;other=dsa").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(versioning.NotFound)
|
||||||
|
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(versioning.NotFound)
|
||||||
|
|
||||||
|
e.GET("/manual").Expect().Status(iris.StatusOK).Body().Equal("11.0.5")
|
||||||
|
}
|
120
versioning/versioning.go
Normal file
120
versioning/versioning.go
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
package versioning
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kataras/iris/context"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-version"
|
||||||
|
)
|
||||||
|
|
||||||
|
// If reports whether the "version" is matching to the "is".
|
||||||
|
// the "is" can be a constraint like ">= 1, < 3".
|
||||||
|
func If(v string, is string) bool {
|
||||||
|
ver, err := version.NewVersion(v)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
constraints, err := version.NewConstraint(is)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return constraints.Check(ver)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match acts exactly the same as `If` does but instead it accepts
|
||||||
|
// a Context, so it can be called by a handler to determinate the requested version.
|
||||||
|
func Match(ctx context.Context, expectedVersion string) bool {
|
||||||
|
return If(GetVersion(ctx), expectedVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map is a map of versions targets to a handlers,
|
||||||
|
// a handler per version or constraint, the key can be something like ">1, <=2" or just "1".
|
||||||
|
type Map map[string]context.Handler
|
||||||
|
|
||||||
|
// NewMatcher creates a single handler which decides what handler
|
||||||
|
// should be executed based on the requested version.
|
||||||
|
//
|
||||||
|
// Use the `NewGroup` if you want to add many routes under a specific version.
|
||||||
|
//
|
||||||
|
// See `Map` and `NewGroup` too.
|
||||||
|
func NewMatcher(versions Map) context.Handler {
|
||||||
|
constraintsHandlers, notFoundHandler := buildConstraints(versions)
|
||||||
|
|
||||||
|
return func(ctx context.Context) {
|
||||||
|
versionString := GetVersion(ctx)
|
||||||
|
if versionString == NotFound {
|
||||||
|
notFoundHandler(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ver, err := version.NewVersion(versionString)
|
||||||
|
if err != nil {
|
||||||
|
notFoundHandler(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ch := range constraintsHandlers {
|
||||||
|
if ch.constraints.Check(ver) {
|
||||||
|
ctx.Header("X-API-Version", ver.String())
|
||||||
|
ch.handler(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass the not matched version so the not found handler can have knowedge about it.
|
||||||
|
// ctx.Values().Set(Key, versionString)
|
||||||
|
// or let a manual cal of GetVersion(ctx) do that instead.
|
||||||
|
notFoundHandler(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type constraintsHandler struct {
|
||||||
|
constraints version.Constraints
|
||||||
|
handler context.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildConstraints(versionsHandler Map) (constraintsHandlers []*constraintsHandler, notfoundHandler context.Handler) {
|
||||||
|
for v, h := range versionsHandler {
|
||||||
|
if v == NotFound {
|
||||||
|
notfoundHandler = h
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
constraints, err := version.NewConstraint(v)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintsHandlers = append(constraintsHandlers, &constraintsHandler{
|
||||||
|
constraints: constraints,
|
||||||
|
handler: h,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if notfoundHandler == nil {
|
||||||
|
notfoundHandler = NotFoundHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
// no sort, the end-dev should declare
|
||||||
|
// all version constraint, i.e < 4.0 may be catch 1.0 if not something like
|
||||||
|
// >= 3.0, < 4.0.
|
||||||
|
// I can make it ordered but I do NOT like the final API of it:
|
||||||
|
/*
|
||||||
|
app.Get("/api/user", NewMatcher( // accepts an array, ordered, see last elem.
|
||||||
|
V("1.0", vHandler("v1 here")),
|
||||||
|
V("2.0", vHandler("v2 here")),
|
||||||
|
V("< 4.0", vHandler("v3.x here")),
|
||||||
|
))
|
||||||
|
instead we have:
|
||||||
|
|
||||||
|
app.Get("/api/user", NewMatcher(Map{ // accepts a map, unordered, see last elem.
|
||||||
|
"1.0": Deprecated(vHandler("v1 here")),
|
||||||
|
"2.0": vHandler("v2 here"),
|
||||||
|
">= 3.0, < 4.0": vHandler("v3.x here"),
|
||||||
|
VersionUnknown: customHandlerForNotMatchingVersion,
|
||||||
|
}))
|
||||||
|
*/
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
136
versioning/versioning_test.go
Normal file
136
versioning/versioning_test.go
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
package versioning_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kataras/iris"
|
||||||
|
"github.com/kataras/iris/httptest"
|
||||||
|
"github.com/kataras/iris/versioning"
|
||||||
|
)
|
||||||
|
|
||||||
|
func notFoundHandler(ctx iris.Context) {
|
||||||
|
ctx.NotFound()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
v10Response = "v1.0 handler"
|
||||||
|
v2Response = "v2.x handler"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sendHandler(contents string) iris.Handler {
|
||||||
|
return func(ctx iris.Context) {
|
||||||
|
ctx.WriteString(contents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIf(t *testing.T) {
|
||||||
|
if expected, got := true, versioning.If("1.0", ">=1"); expected != got {
|
||||||
|
t.Fatalf("expected %s to be %s", "1.0", ">= 1")
|
||||||
|
}
|
||||||
|
if expected, got := true, versioning.If("1.2.3", "> 1.2"); expected != got {
|
||||||
|
t.Fatalf("expected %s to be %s", "1.2.3", "> 1.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestNewMatcher(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
userAPI := app.Party("/api/user")
|
||||||
|
userAPI.Get("/", versioning.NewMatcher(versioning.Map{
|
||||||
|
"1.0": sendHandler(v10Response),
|
||||||
|
">= 2, < 3": sendHandler(v2Response),
|
||||||
|
versioning.NotFound: notFoundHandler,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// middleware as usual.
|
||||||
|
myMiddleware := func(ctx iris.Context) {
|
||||||
|
ctx.Header("X-Custom", "something")
|
||||||
|
ctx.Next()
|
||||||
|
}
|
||||||
|
myVersions := versioning.Map{
|
||||||
|
"1.0": sendHandler(v10Response),
|
||||||
|
}
|
||||||
|
|
||||||
|
userAPI.Get("/with_middleware", myMiddleware, versioning.NewMatcher(myVersions))
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "1").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v10Response)
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.0").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.1").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.9.9").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
|
||||||
|
// middleware as usual.
|
||||||
|
ex := e.GET("/api/user/with_middleware").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect()
|
||||||
|
ex.Status(iris.StatusOK).Body().Equal(v10Response)
|
||||||
|
ex.Header("X-Custom").Equal("something")
|
||||||
|
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "3.0").Expect().
|
||||||
|
Status(iris.StatusNotFound).Body().Equal("Not Found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewGroup(t *testing.T) {
|
||||||
|
app := iris.New()
|
||||||
|
|
||||||
|
userAPI := app.Party("/api/user")
|
||||||
|
// [... static serving, middlewares and etc goes here].
|
||||||
|
|
||||||
|
userAPIV10 := versioning.NewGroup("1.0").Deprecated(versioning.DefaultDeprecationOptions)
|
||||||
|
// V10middlewareResponse := "m1"
|
||||||
|
// userAPIV10.Use(func(ctx iris.Context) {
|
||||||
|
// println("exec userAPIV10.Use - midl1")
|
||||||
|
// sendHandler(V10middlewareResponse)(ctx)
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
// userAPIV10.Use(func(ctx iris.Context) {
|
||||||
|
// println("exec userAPIV10.Use - midl2")
|
||||||
|
// sendHandler(V10middlewareResponse + "midl2")(ctx)
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
// userAPIV10.Use(func(ctx iris.Context) {
|
||||||
|
// println("exec userAPIV10.Use - midl3")
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
|
||||||
|
userAPIV10.Get("/", sendHandler(v10Response))
|
||||||
|
userAPIV2 := versioning.NewGroup(">= 2, < 3")
|
||||||
|
// V2middlewareResponse := "m2"
|
||||||
|
// userAPIV2.Use(func(ctx iris.Context) {
|
||||||
|
// println("exec userAPIV2.Use - midl1")
|
||||||
|
// sendHandler(V2middlewareResponse)(ctx)
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
// userAPIV2.Use(func(ctx iris.Context) {
|
||||||
|
// println("exec userAPIV2.Use - midl2")
|
||||||
|
// ctx.Next()
|
||||||
|
// })
|
||||||
|
|
||||||
|
userAPIV2.Get("/", sendHandler(v2Response))
|
||||||
|
userAPIV2.Post("/", sendHandler(v2Response))
|
||||||
|
userAPIV2.Put("/other", sendHandler(v2Response))
|
||||||
|
|
||||||
|
versioning.RegisterGroups(userAPI, versioning.NotFoundHandler, userAPIV10, userAPIV2)
|
||||||
|
|
||||||
|
e := httptest.New(t, app)
|
||||||
|
|
||||||
|
ex := e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "1").Expect()
|
||||||
|
ex.Status(iris.StatusOK).Body().Equal(v10Response)
|
||||||
|
ex.Header("X-API-Warn").Equal(versioning.DefaultDeprecationOptions.WarnMessage)
|
||||||
|
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.0").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.1").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2.9.9").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
e.POST("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "2").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
e.PUT("/api/user/other").WithHeader(versioning.AcceptVersionHeaderKey, "2.9").Expect().
|
||||||
|
Status(iris.StatusOK).Body().Equal(v2Response)
|
||||||
|
|
||||||
|
e.GET("/api/user").WithHeader(versioning.AcceptVersionHeaderKey, "3.0").Expect().
|
||||||
|
Status(iris.StatusNotImplemented).Body().Equal("version not found")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user